var CORE_ENGINE_VERSION = "1.2",
    CORE_ENGINE_API_LEVEL = 8,
    CORE_ENGINE_CONFIG_LOCK = 4;

function getMCPEVersion() {
    var a = {
        str: ModPE.getMinecraftVersion() + ""
    };
    a.array = a.str.split(".");
    for (var b in a.array) a.array[b] = parseInt(a.array[b]) || 0;
    a.main = a.array[1] + 17 * a.array[0];
    return a
}
var MCPE_VERSION = getMCPEVersion(),
    MCPE_VERSION_SUPPORT = {
        14: !0,
        15: !0,
        16: !0,
        17: !0
    };

function RestartBlocklauncher() {
    print("restarting blocklauncher & core engine...");
    net.zhuoweizhang.mcpelauncher.ui.NerdyStuffActivity.forceRestart(getMcContext())
}
15 == MCPE_VERSION.main && (Block.setDestroyTime = function() {});
16 == MCPE_VERSION.main && (ModPE.showTipMessage = function() {});
var FileTools = {
    mntdir: "/mnt",
    root: android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/",
    workdir: "games/com.mojang/coreengine/",
    moddir: "games/com.mojang/mods/",
    modpedir: "games/com.mojang/modpe/",
    mkdir: function(a) {
        (new java.io.File(this.root + a)).mkdirs()
    },
    mkworkdirs: function() {
        this.mkdir(this.workdir);
        this.mkdir(this.moddir);
        this.mkdir(this.modpedir)
    },
    getFullPath: function(a) {
        a = new String(a);
        return a.startsWith(this.root) || a.startsWith(this.mntdir) ? a : this.root + a
    },
    isExists: function(a) {
        return (new java.io.File(this.getFullPath(a))).exists()
    },
    WriteText: function(a, b, c) {
        a = this.getFullPath(a);
        c = new java.io.PrintWriter(new java.io.BufferedWriter(new java.io.FileWriter(a, c || !1)));
        c.write(b);
        c.close()
    },
    ReadText: function(a) {
        a = this.getFullPath(a);
        try {
            var b = java.io.BufferedReader(new java.io.FileReader(a)),
                c;
            for (a = ""; c = b.readLine();) a += c + "\n";
            return a
        } catch (d) {
            return null
        }
    },
    WriteImage: function(a, b) {
        var c = new java.io.FileOutputStream(this.getFullPath(a));
        b.compress(android.graphics.Bitmap.CompressFormat.PNG, 100, c)
    },
    ReadImage: function(a) {
        var b = new android.graphics.BitmapFactory.Options;
        b.inScaled = !1;
        try {
            return android.graphics.BitmapFactory.decodeFile(this.getFullPath(a), b)
        } catch (c) {
            return null
        }
    },
    ReadTextAsset: function(a) {
        return (a = ModPE.getBytesFromTexturePack("assets/" + a)) ? new java.lang.String(a) : null
    },
    ReadImageAsset: function(a) {
        a = ModPE.getBytesFromTexturePack("assets/" + a);
        var b = new android.graphics.BitmapFactory.Options;
        b.inScaled = !1;
        return a ? android.graphics.BitmapFactory.decodeByteArray(a, 0, a.length, b) : null
    },
    ReadBytesAsset: function(a) {
        return (a = ModPE.getBytesFromTexturePack("assets/" +
            a)) ? a : null
    },
    GetListOfDirs: function(a) {
        var b = [];
        a = (new java.io.File(this.getFullPath(a))).listFiles();
        if (!a) return b;
        for (var c = 0; c < a.length; c++) {
            var d = a[c];
            d.isDirectory() && b.push(d)
        }
        return b
    },
    GetListOfFiles: function(a, b) {
        var c = [],
            d = (new java.io.File(this.getFullPath(a))).listFiles();
        if (!d) return c;
        for (var e = 0; e < d.length; e++) {
            var f = d[e];
            f.isDirectory() || b && !f.getName().endsWith(b) || c.push(f)
        }
        return c
    },
    ReadKeyValueFile: function(a, b) {
        var c = b || ":",
            d = this.ReadText(a);
        if (!d) return {};
        var d = d.split("\n"),
            e = {},
            f;
        for (f in d) {
            var g = d[f].split(c);
            2 == g.length && (e[g[0]] = g[1])
        }
        return e
    },
    WriteKeyValueFile: function(a, b, c) {
        c = c || ":";
        var d = [],
            e;
        for (e in b) d.push(e + c + b[e]);
        b = d.join("\n");
        this.WriteText(a, b)
    },
    ReadJSON: function(a) {
        a = this.ReadText(a);
        try {
            return JSON.parse(a) || {}
        } catch (b) {
            return {}
        }
    },
    WriteJSON: function(a, b, c) {
        b = b || {};
        b = JSON.stringify(b, null, c ? "\t" : null);
        this.WriteText(a, b)
    }
};
FileTools.mkworkdirs();
var DataSaver = {
        path: "/",
        beautify: !0,
        dataObject: {},
        refreshPath: function() {
            this.path = "games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/moddata.json"
        },
        readJSON: function() {
            this.dataObject = {};
            var a = FileTools.ReadText(this.path);
            try {
                this.dataObject = JSON.parse(a) || {}
            } catch (b) {
                Logger.Log("failed to read json saves for " + this.path, "WARNING")
            }
        },
        writeJSON: function() {
            var a = JSON.stringify(this.dataObject, null, this.beautify ? "\t" : null);
            FileTools.WriteText(this.path, a)
        }
    },
    SavesFunctions = {
        read: function() {
            DataSaver.refreshPath();
            DataSaver.readJSON();
            Callback.invokeCallback("ReadSaves", DataSaver.dataObject)
        },
        write: function() {
            this.dataObject = {};
            Callback.invokeCallback("WriteSaves", DataSaver.dataObject);
            DataSaver.writeJSON()
        }
    },
    LOG_MAX_LIST_LENGTH = 8,
    Logger = {
        MAX_BUFFER_LEN: 1024,
        CORE: "core.log",
        MOD: "mods.log",
        shared: "",
        hasErrorMessages: !1,
        wipe: function(a) {
            this.buffer[a] = "";
            FileTools.WriteText(FileTools.workdir + a, "", !1)
        },
        buffer: {},
        message: function(a, b) {
            this.shared += b + "\n";
            this.buffer[a] = (this.buffer[a] || "") + b + "\n";
            this.buffer[a] &&
                this.buffer[a].length > this.MAX_BUFFER_LEN && this.flush(a)
        },
        flush: function(a) {
            a ? this.buffer[a] && (FileTools.WriteText(FileTools.workdir + a, this.buffer[a], !0), this.buffer[a] = "") : (this.flush(this.CORE), this.flush(this.MOD))
        },
        formatLog: function(a) {
            var b = a.split("\n");
            a = [];
            for (var c in b) {
                var d = b[c];
                if (d.startsWith("[")) {
                    e && a.push(e);
                    var e = ""
                }
                e += d + "\n"
            }
            e && a.push(e);
            e = {
                ERROR: !0
            };
            var b = {
                    WARNING: !0
                },
                d = {
                    LOADER: !0
                },
                f = {
                    MOD: !0
                },
                g = {
                    UNLIMITED: !0,
                    API: !0
                },
                h = {
                    CORE: !0
                },
                k = "";
            for (c in a) {
                var m = a[c],
                    l = m.indexOf("["),
                    n = m.indexOf("]");
                if (-1 != l && -1 != n) {
                    var l = m.substr(l + 1, n - 1),
                        m = m.substr(n + 1, m.length),
                        n = "<font>",
                        r = "";
                    e[l] && (n = "<font color='#AA0000'>");
                    b[l] && (n = "<font color='#CCAA00'>");
                    d[l] && (n = "<font color='#00BB00'>");
                    f[l] && (r = "</font><font face='calibri'>");
                    g[l] && (n = "<font color='#0000FF'>");
                    h[l] && (n = "<font color='#AA00AA'>");
                    k += n + "<b>[" + l + "]</b>" + r + m + "</font>"
                }
            }
            return k
        },
        formatItem: function(a, b, c) {
            return "[" + (IdentifierRegistry.reversedData.item[a] || IdentifierRegistry.reversedData.block[a] || "" + a) + ":" + c + " * " + b + "]"
        },
        showAsDialog: function(a,
            b) {
            var c = this.shared;
            b && (c = b + c);
            c = this.formatLog(c);
            GameAPI.dialogMessage(c, a || "current log")
        },
        Log: function(a, b, c) {
            b = b || "STDOUT";
            c = c || this.CORE;
            "ERROR" == b && (this.hasErrorMessages = !0);
            this.message(c, "[" + b + "] " + a)
        },
        LogError: function(a, b) {
            var c = "";
            a && (c += a + "\n" + a.stack);
            this.Log(c, "ERROR", b)
        },
        LogList: function(a, b, c, d) {
            var e = "",
                f;
            for (f in b) {
                if (f >= LOG_MAX_LIST_LENGTH) {
                    e += "..." + (b.length - f) + " more";
                    break
                }
                f < b.length - 1 && (e += b[f] + ", ")
            }
            this.Log(a + e, c, d)
        },
        getFormattedTime: function(a) {
            var b = java.lang.System.currentTimeMillis(),
                b = new java.util.Date(b),
                c = "HH:mm:ss";
            a && (c = "dd.MM.yyyy HH:mm:ss");
            return (new java.text.SimpleDateFormat(c)).format(b)
        },
        getShared: function() {
            return this.shared
        },
        getFormattedLog: function() {
            return this.formatLog(this.shared + "")
        },
        checkErrors: function() {
            Logger.hasErrorMessages && Logger.showAsDialog(null, "loading log contains some errors: ")
        }
    };
Logger.wipe(Logger.CORE);
Logger.wipe(Logger.MOD);
Logger.message(Logger.CORE, "");
Logger.message(Logger.CORE, "");
Logger.Log("Core Engine started", "CORE");
Logger.Log("-- current time: " + Logger.getFormattedTime(!0), "CORE");
Logger.Log("-- MCPE version: " + MCPE_VERSION.str + " (" + MCPE_VERSION.main + "th generation)", "CORE");
Logger.Log("-- Core Engine version: " + CORE_ENGINE_VERSION + " (api level " + CORE_ENGINE_API_LEVEL + ")", "CORE");
try {
    Logger.Log("-- android API level: " + android.os.Build.VERSION.SDK_INT, "CORE")
} catch (a) {}
MCPE_VERSION_SUPPORT[MCPE_VERSION.main] ? Logger.Log("Current MCPE version (" + MCPE_VERSION.str + ") is supported by Core Engine, it will work stable", "CORE") : Logger.Log("Current MCPE version (" + MCPE_VERSION.str + ") is not supported by Core Engine, it may work unstable and unsave", "ERROR");

function CheckAllTexturePacks() {
    var a = net.zhuoweizhang.mcpelauncher.Utils,
        b = a.getPrefs(0).edit(),
        c = a.getPrefs(1).edit();
    b.putBoolean("zz_texture_pack_enable", !0);
    b.apply();
    var b = !1,
        a = JSON.parse(a.getPrefs(1).getString("texture_packs", "[]")),
        d;
    for (d in a) a[d] && !(new java.io.File(a[d].p)).exists() && (Logger.Log("found and removed missing textures: " + a[d].p + ": core engine will be restarted", "LOADER", "files.log"), a.splice(d--, 1), b = !0);
    Logger.flush("files.log");
    c.putString("texture_packs", JSON.stringify(a));
    c.apply();
    b && RestartBlocklauncher()
}
CheckAllTexturePacks();
var Callback = {
        callbacks: {},
        formatCallbackError: function(a, b) {
            var c = "Error occured in callback " + a + "\n\nDETAILS:\n" + ("mod: " + b.fileName + "\n");
            c += "line: " + b.lineNumber + "\n";
            return c += "stacktrace: <font color='#CC0000'>\n" + b.message + "\n" + b.stack + "</font>"
        },
        addCallback: function(a, b, c) {
            this.callbacks[a] || (this.callbacks[a] = []);
            this.callbacks[a].push({
                name: a,
                func: b,
                mod: c
            })
        },
        invokeCallback: function(a, b, c, d, e, f, g, h, k, m) {
            for (var l in this.callbacks[a]) {
                var n = this.callbacks[a][l];
                try {
                    n.func(b, c, d, e, f, g, h, k,
                        m)
                } catch (r) {
                    Logger.Log("callback " + a + " error: " + r, "ERROR"), Logger.LogError(r), n = this.formatCallbackError(a, r), GameAPI.dialogMessage(n, "CALLBACK ERROR")
                }
            }
        }
    },
    Threading = {
        threads: [],
        formatFatalErrorMessage: function(a, b, c, d) {
            var e = "Fatal error detected in thread " + b + ", all mods on this thread shutted down. Exit world safely and restart. \n\n \u041a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 " + b + ", \u0432\u0441\u0435 \u043c\u043e\u0434\u044b \u0432 \u044d\u0442\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u044b. \u0414\u043b\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0433\u043e \u0432\u044b\u0445\u043e\u0434\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u0435 \u043c\u0438\u0440 \u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435\u0441\u044c.\n\nCRASH INFO:\n";
            e = d ? e + d(a, c) : e + ("thread name: " + b + "\nthread priority:" + c);
            e = e + "\n\nERROR DETAILS: \n" + ("mod: " + a.fileName + "\n");
            e += "line: " + a.lineNumber + "\n";
            e += "stacktrace: <font color='#CC0000'>\n" + a.message + "\n" + a.stack + "</font>";
            a = Logger.getFormattedLog();
            return e + "\n\nLOG:\n" + a
        },
        initThread: function(a, b, c, d, e) {
            var f = new java.lang.Thread({
                run: function() {
                    try {
                        android.os.Process.setThreadPriority(parseInt(c) || 0), b()
                    } catch (h) {
                        if (Logger.Log("fatal error in thread " + a + ": " + h, "ERROR"), Logger.LogError(h), Logger.flush(),
                            d) {
                            var f = Threading.formatFatalErrorMessage(h, a, c, e);
                            GameAPI.dialogMessage(f, "FATAL ERROR")
                        }
                    }
                    delete Threading.threads[a]
                }
            });
            Threading.threads[a] = f;
            f.start();
            return f
        },
        getThread: function(a) {
            return this.threads[a]
        }
    },
    DataBridge = {
        stac: [],
        callbacks: {},
        addDataCallback: function(a, b) {
            this.callbacks[a] || (this.callbacks[a] = [])
        }
    },
    ModAPI = {
        modAPIs: {},
        registerAPI: function(a, b, c) {
            c || (c = {});
            c.name || (c.name = a);
            c.props || (c.props = {});
            this.modAPIs[a] = {
                api: b,
                descr: c
            };
            Callback.invokeCallback("API:" + a, b, c)
        },
        requireAPI: function(a) {
            return this.modAPIs[a] ?
                this.modAPIs[a].api || null : null
        },
        requireGlobal: function(a) {
            try {
                return eval(a)
            } catch (b) {
                return Logger.Log("ModAPI.requireGlobal for " + a + " failed: " + b, "ERROR"), null
            }
        },
        requireAPIdoc: function(a) {
            return this.modAPIs[a] ? this.modAPIs[a].descr || null : null
        },
        requireAPIPropertyDoc: function(a, b) {
            var c = this.requireAPIdoc(a);
            return c ? c.props[b] || null : null
        },
        getModByName: function(a) {
            if (modList)
                for (var b in modList) {
                    var c = modList[b];
                    if (c.modName == a) return c
                }
            return null
        },
        isModLoaded: function(a) {
            return this.getModByName(a)
        },
        addAPICallback: function(a, b) {
            this.modAPIs[a] ? b(this.requireAPI(a)) : Callback.addCallback("API:" + a, b)
        },
        addModCallback: function(a, b) {
            this.isModLoaded(a) ? b(this.getModByName(a)) : Callback.addCallback("ModLoaded:" + a, b)
        },
        getModList: function() {
            return modList
        },
        getModPEList: function() {
            return modpeScriptList
        },
        addTexturePack: function(a) {
            a = new java.io.File(FileTools.getFullPath(a));
            addTexturePack(a)
        },
        cloneAPI: function(a, b) {
            var c = {},
                d;
            for (d in a) {
                var e = a[d];
                c[d] = b && e && (e.push || "[object Object]" == e + "") ? this.cloneAPI(e, !1) : e
            }
            return c
        },
        inheritPrototypes: function(a, b) {
            for (var c in a) b[c] || (b[c] = a[c]);
            return b
        },
        cloneObject: function(a, b, c) {
            c || (c = 0);
            if (6 < c) return Logger.Log("object clone failed: stackoverflow at " + a, "WARNING"), a;
            if ("undefined" != a + "") {
                if (null == a) return null;
                var d = {},
                    e;
                for (e in a) {
                    var f = a[e];
                    d[e] = b && "object" == typeof f ? this.cloneObject(f, !0, c + 1) : f
                }
                return d
            }
        },
        debugCloneObject: function(a, b, c) {
            c || (c = 0);
            if (5 < c) return "stackoverflow";
            if ("undefined" != a + "") {
                if (null == a) return null;
                var d = {},
                    e;
                for (e in a) {
                    var f = a[e];
                    d[e] = b && "object" == typeof f ? this.cloneObject(f, !0, c + 1) : f
                }
                return d
            }
        }
    },
    SaverAPI = {
        saverScopes: {},
        addSavesScope: function(a, b, c) {
            for (var d = a = "M_" + a; this.saverScopes[a];) a += "_";
            d != a && Logger.Log("saves scope " + d + " is unstable, name is not unique, change it (temporary name is " + a + ") ", "WARNING");
            this.saverScopes[a] = {
                loader: b || function(a) {},
                saver: c || function() {
                    return null
                }
            }
        },
        onAllLoaded: function(a) {
            for (var b in this.saverScopes) this.saverScopes[b].loader(a[b] || {})
        },
        onAllSaved: function(a) {
            for (var b in this.saverScopes) {
                var c =
                    this.saverScopes[b].saver() || {};
                a[b] = c
            }
        }
    };
Callback.addCallback("WriteSaves", function(a) {
    SaverAPI.onAllSaved(a)
});
Callback.addCallback("ReadSaves", function(a) {
    SaverAPI.onAllLoaded(a)
});
var GameAPI = {
    prevent: function() {
        preventDefault()
    },
    message: function(a) {
        clientMessage(a + "")
    },
    tipMessage: function(a) {
        ModPE.showTipMessage(a + "")
    },
    dialogMessage: function(a, b) {
        GuiUtils.Run(function() {
            var c = getMcContext(),
                c = android.app.AlertDialog.Builder(c);
            b && c.setTitle(b + "");
            a && (a += "", a = a.split("\n").join("<br>"), c.setMessage(android.text.Html.fromHtml(a)));
            c.show()
        })
    },
    setDifficulty: function(a) {
        Level.setDifficulty(a)
    },
    getDifficulty: function() {
        return Level.getDifficulty()
    },
    getI18n: function(a) {
        return ModPE.getI18n(a)
    },
    getMinecraftVersion: function() {
        ModPE.getMinecraftVersion()
    },
    getEngineVersion: function() {
        return CORE_ENGINE_VERSION
    },
    selectLevel: function(a) {
        ModPE.selectLevel(a)
    },
    setCamera: function(a) {
        ModPE.setCamera(a)
    },
    setTickingSpeed: function(a) {
        ModPE.setGameSpeed(parseInt(20 * (a || 0)))
    },
    setRenderDebug: function(a) {
        ModPE.setUiRenderDebug(a)
    },
    screenshot: function(a) {
        ModPE.takeScreenshot(a)
    }
};

function Updatable(a) {
    this.update = a;
    this.remove = !1;
    this.destroy = function() {
        this.remove = !0
    }
}
var UpdatableAPI = {
        updatableList: [],
        uniqueUpdatableMap: [],
        uniqueUpdatableID: 1,
        maximumCalls: 64,
        setMaxUpdateCalls: function(a) {
            this.maximumCalls = parseInt(a) || 64;
            Logger.Log("max update calls set to " + this.maximumCalls, "API")
        },
        addUpdatable: function(a) {
            this.isInUpdate(a) || (a.uuID = ++this.uniqueUpdatableID, this.uniqueUpdatableMap[a.uuID] = a, this.updatableList.push(a))
        },
        removeUpdatable: function(a) {
            if (a) {
                var b = a.uuID;
                b && (delete this.uniqueUpdatableMap[b], a.uuID = -1);
                return a.remove = !0
            }
        },
        isInUpdate: function(a) {
            if (a &&
                a.uuID) return this.uniqueUpdatableMap[a.uuID]
        },
        removeUpdatableFast: function(a) {
            delete this.uniqueUpdatableMap[a.uuID];
            a.uuID = -1;
            a.remove = !0
        },
        removesUpdatableByID: function(a) {
            this.uniqueUpdatableMap[uuID] && (a = this.uniqueUpdatableMap[uuID], a.uuID = -1, a.remove = !0, delete this.uniqueUpdatableMap[uuID])
        },
        getUpdatable: function(a) {
            return this.uniqueUpdatableMap[a]
        },
        previousPosition: 0,
        updateAll: function() {
            if (0 != this.updatableList.length) {
                this.previousPosition %= this.updatableList.length;
                for (var a = Math.min(this.updatableList.length,
                        this.maximumCalls), b = this.previousPosition, c = 0; c < a; c++) {
                    var d = this.updatableList[b];
                    if (d && (d.update(), d.remove)) {
                        this.updatableList.splice(b, 1);
                        this.removeUpdatableFast(d);
                        continue
                    }
                    java.lang.Thread.yield();
                    b = (b + 1) % this.updatableList.length
                }
                this.previousPosition = b || 0
            }
        },
        resetEngine: function() {
            for (var a in this.updatableList) {
                var b = this.updatableList[a];
                if (b.onEngineReset) b.onEngineReset()
            }
            this.updatableList = [];
            this.uniqueUpdatableMap = [];
            this.previousPosition = 0
        }
    },
    DefaultSaverPrototype = {
        update: function() {},
        save: function() {
            return {}
        },
        read: function(a) {}
    },
    UpdatableSaver = {
        saverPrototypes: {},
        registerPrototype: function(a, b) {
            b.__SAVER_PROTOTYPE__ = a;
            this.saverPrototypes[a] = b
        },
        attachSaverPrototype: function(a, b) {
            return this.saverPrototypes[b] ? (a.__SAVER_PROTOTYPE__ = b, a.save = this.saverPrototypes[b].save, a.read = this.saverPrototypes[b].read, !0) : !1
        },
        readUpdatable: function(a) {
            return a && a.TYPE ? this.readUpdatableByPrototype(a.TYPE, a.savedData || {}) : null
        },
        readUpdatableByPrototype: function(a, b) {
            var c = this.saverPrototypes[a];
            if (c) {
                var d = {},
                    e;
                for (e in DefaultSaverPrototype) d[e] = DefaultSaverPrototype[e];
                for (e in c) d[e] = c[e];
                d = ModAPI.cloneObject(d, !0);
                d.read(b) || UpdatableAPI.addUpdatable(d);
                return d
            }
            return null
        },
        writeUpdatable: function(a) {
            var b = a.__SAVER_PROTOTYPE__;
            return b && this.saverPrototypes[b] ? (a = a.save(), {
                TYPE: b,
                savedData: a
            }) : {}
        },
        saveAllUpdatables: function(a) {
            a._updatables = [];
            for (var b in UpdatableAPI.updatableList) {
                var c = UpdatableAPI.updatableList[b];
                c.__SAVER_PROTOTYPE__ && a._updatables.push(this.writeUpdatable(c))
            }
        },
        readAllUpdatables: function(a) {
            for (var b in a._updatables) this.readUpdatable(a._updatables[b])
        }
    };
Callback.addCallback("WriteSaves", function(a) {
    UpdatableSaver.saveAllUpdatables(a)
});
Callback.addCallback("ReadSaves", function(a) {
    UpdatableSaver.readAllUpdatables(a)
});

function GameObject(a, b) {
    if (this.originalName = this.gameobjectName = a) this.gameobjectName = GameObjectRegistry.genUniqueName(this.gameobjectName), GameObjectRegistry.registerClass(this);
    this.isDeployed = this.isInstance = !1;
    this.Prototype = b;
    this.instantiate = function() {
        var a = {},
            b;
        for (b in this) a[b] = this[b];
        for (b in this.Prototype) a[b] = this.Prototype[b];
        a.isInstance = !0;
        this.gameobjectName && UpdatableSaver.attachSaverPrototype(a, this.gameobjectName);
        return a
    };
    this.deploy = function() {
        var a = this.instantiate();
        a.init &&
            a.init.apply(a, arguments);
        GameObjectRegistry.deployGameObject(a);
        return a
    };
    this.destroy = function() {
        this.isInstance && (this.remove = !0, GameObjectRegistry.removeGameObject(this))
    };
    this.save = function() {
        return this
    };
    this.read = function(a) {
        var b = this.instantiate(),
            c;
        for (c in a) b[c] = a[c];
        b.isDeployed = !1;
        b.isInstance = !0;
        GameObjectRegistry.deployGameObject(b);
        return !0
    }
}
var GameObjectRegistry = {
        gameObjectTypes: {},
        activeGameObjects: {},
        genUniqueName: function(a) {
            for (a += ""; this.gameObjectTypes[a];) a = "_" + a;
            return a
        },
        registerClass: function(a) {
            this.gameObjectTypes[a.gameobjectName] = a;
            UpdatableSaver.registerPrototype(a.gameobjectName, a)
        },
        deployGameObject: function(a) {
            if (a.isDeployed) Logger.Log("trying to deploy game object (" + a.originalName + ") while its already in update", "WARNING");
            else return UpdatableAPI.addUpdatable(a), this.addGameObject(a), a.loaded && a.loaded(), a
        },
        addGameObject: function(a) {
            a.originalName &&
                !a.isDeployed && (this.activeGameObjects[a.originalName] || (this.activeGameObjects[a.originalName] = []), this.activeGameObjects[a.originalName].push(a));
            a.isDeployed = !0
        },
        removeGameObject: function(a) {
            if (a.originalName && a.isDeployed) {
                var b = this.activeGameObjects[a.originalName],
                    c;
                for (c in b)
                    if (b[c] == a) {
                        b.splice(c, 1);
                        break
                    }
            }
            a.isDeployed = !1
        },
        resetEngine: function() {
            this.activeGameObjects = {}
        },
        getAllByType: function(a, b) {
            if (b) {
                var c = this.activeGameObjects[a],
                    d = [],
                    e;
                for (e in c) d.push(c[e]);
                return d
            }
            return this.activeGameObjects[a] || []
        },
        callForType: function() {
            var a = [];
            for (b in arguments) a.push(arguments[b]);
            var b = a.shift();
            var c = a.shift(),
                d = this.getAllByType(b);
            for (b = 0; b < d.length; b++) {
                var e = d[b];
                e[c] && e[c].apply(e, a)
            }
        },
        callForTypeSafe: function() {
            var a = [];
            for (b in arguments) a.push(arguments[b]);
            var b = a.shift();
            var c = a.shift(),
                d = this.getAllByType(b, !0);
            for (b = 0; b < d.length; b++) {
                var e = d[b];
                e[c] && e[c].apply(e, a)
            }
        }
    },
    TileEntityBasePrototype = {
        remove: !1,
        isLoaded: !1,
        __initialized: !1,
        defaultValues: {},
        update: function() {
            this.__initialized ||
                (this.init(), this.__initialized = !0);
            this.isLoaded && this.tick()
        },
        created: function() {},
        init: function() {},
        tick: function() {},
        click: function(a, b, c, d) {
            return !1
        },
        destroyBlock: function(a, b) {},
        redstone: function(a) {},
        projectileHit: function(a, b) {},
        destroy: function() {
            return !1
        },
        getGuiScreen: function() {
            return null
        },
        onItemClick: function(a, b, c, d) {
            if (this.click(a, b, c)) return !0;
            if (Entity.isSneaking(getPlayerEnt())) return !1;
            if (a = this.getGuiScreen()) return this.container.openAs(a), !0
        },
        selfDestroy: function() {
            TileEntity.destroyTileEntity(this)
        },
        requireMoreLiquid: function(a, b) {},
        save: function() {
            return {
                data: this.data,
                container: this.container.save(),
                liquidStorage: this.liquidStorage.save(),
                coords: {
                    x: this.x,
                    y: this.y,
                    z: this.z
                }
            }
        },
        read: function(a) {
            this.data = a.data;
            this.container = new Container(this);
            this.container.read(a.container || {});
            this.liquidStorage = new LiquidRegistry.Storage(this);
            this.liquidStorage.read(a.liquidStorage || {});
            this.x = a.coords.x;
            this.y = a.coords.y;
            this.z = a.coords.z;
            TileEntity.addUpdatableAsTileEntity(this)
        }
    },
    TILE_ENTITY_CHECKER_ITERATIONS =
    10,
    TileEntity = {
        tileEntityPrototypes: {},
        tileEntityList: [],
        resetEngine: function() {
            this.tileEntityList = []
        },
        registerPrototype: function(a, b) {
            var c = {},
                d;
            for (d in TileEntityBasePrototype) c[d] = TileEntityBasePrototype[d];
            for (d in b) c[d] = b[d];
            c.blockID = a;
            this.tileEntityPrototypes[a] = c;
            UpdatableSaver.registerPrototype("_TILE_ENTITY" + a, c)
        },
        getPrototype: function(a) {
            return this.tileEntityPrototypes[a]
        },
        isTileEntityBlock: function(a) {
            return this.tileEntityPrototypes[a] ? !0 : !1
        },
        createTileEntityForPrototype: function(a,
            b) {
            var c = {},
                d;
            for (d in a) c[d] = a[d];
            c.data = {};
            for (d in a.defaultValues) c.data[d] = a.defaultValues[d];
            c.container = new Container(c);
            c.liquidStorage = new LiquidRegistry.Storage(c);
            b && (UpdatableAPI.addUpdatable(c), c.remove = !1, c.isLoaded = !0);
            return c
        },
        addTileEntity: function(a, b, c) {
            if (this.getTileEntity(a, b, c)) return null;
            var d = getTile(a, b, c);
            return (d = this.getPrototype(d)) ? (d = this.createTileEntityForPrototype(d, !0), d.x = a, d.y = b, d.z = c, this.tileEntityList.push(d), d.created(), d) : null
        },
        addUpdatableAsTileEntity: function(a) {
            a.remove = !1;
            a.isLoaded = !0;
            this.tileEntityList.push(a)
        },
        getTileEntity: function(a, b, c) {
            for (var d in this.tileEntityList) {
                var e = this.tileEntityList[d];
                if (e.x == a && e.y == b && e.z == c) return e
            }
            return null
        },
        destroyTileEntity: function(a) {
            if (a.destroy()) return !1;
            a.remove = !0;
            a.container.dropAt(a.x + .5, a.y + .5, a.z + .5);
            for (var b in this.tileEntityList) this.tileEntityList[b] == a && this.tileEntityList.splice(b--, 1);
            return !0
        },
        destroyTileEntityAtCoords: function(a, b, c) {
            return (a = this.getTileEntity(a, b, c)) ? this.destroyTileEntity(a) :
                !1
        },
        CheckTileEntities: function() {
            var a = TickingThread.getTime();
            0 < this.tileEntityList.length && (a = this.tileEntityList[a % this.tileEntityList.length], a.isLoaded = 0 < getTile(a.x, 0, a.z), a.isLoaded && getTile(a.x, a.y, a.z) != a.blockID && this.DeployDestroyChecker(a))
        },
        DeployDestroyChecker: function(a) {
            a.__checkInProgress || (a.__checkInProgress = !0, UpdatableAPI.addUpdatable({
                tileEntity: a,
                age: 0,
                update: function() {
                    getTile(this.tileEntity.x, this.tileEntity.y, this.tileEntity.z) == a.blockID ? (this.tileEntity.__checkInProgress = !1, this.remove = !0) : this.age++ > TILE_ENTITY_CHECKER_ITERATIONS && (TileEntity.destroyTileEntity(this.tileEntity), this.tileEntity.__checkInProgress = !1, this.remove = !0)
                }
            }))
        }
    };
Callback.addCallback("RedstoneSignal", function(a, b, c) {
    (a = TileEntity.getTileEntity(a.x, a.y, a.z)) && a.redstone(b)
});
Callback.addCallback("DestroyBlock", function(a, b, c) {
    if (b = TileEntity.getTileEntity(a.x, a.y, a.z)) b.destroyBlock(a, c), TileEntity.destroyTileEntity(b)
});
Callback.addCallback("ProjectileHitBlock", function(a, b, c) {
    (c = TileEntity.getTileEntity(b.x, b.y, b.z)) && c.projectileHit(b, a)
});
var WorldGeneration = {
        generatorUpdatable: null,
        checkTile: function(a, b) {
            if (8 != WorldAPI.nativeGetBlockData(a, 0, b)) return 0 != WorldAPI.nativeGetBlockID(a, 0, b)
        },
        execGeneration: function(a, b, c) {
            var d = function() {
                1 == b ? Callback.invokeCallback("GenerateNetherChunk", a.x, a.z) : 2 == b ? Callback.invokeCallback("GenerateEndChunk", a.x, a.z) : c ? Callback.invokeCallback("GenerateChunkUnderground", a.x, a.z) : Callback.invokeCallback("GenerateChunk", a.x, a.z);
                c ? WorldAPI.nativeSetBlock(16 * a.x + 1, 0, 16 * a.z + 1, 7, 8) : WorldAPI.nativeSetBlock(16 *
                    a.x, 0, 16 * a.z, 7, 8)
            };
            this.thread_optimization ? (android.os.Process.setThreadPriority(this.generation_priority || 0), d(), android.os.Process.setThreadPriority(this.ticking_priority || 0)) : MainThread.push(d)
        },
        processChunk: function(a, b, c) {
            b = Math.max(Math.abs(a.x - b.x), Math.abs(a.z - b.z));
            b <= this.generatorUpdatable.surface_radius && WorldGeneration.checkTile(16 * a.x, 16 * a.z) && WorldGeneration.execGeneration(a, c, !1);
            b <= this.generatorUpdatable.underground_radius && 0 == c && 64 > getPlayerY() && WorldGeneration.checkTile(16 * a.x +
                1, 16 * a.z + 1) && WorldGeneration.execGeneration(a, c, !0)
        },
        resetEngine: function() {
            this.generatorUpdatable && (this.generatorUpdatable.remove = !0);
            this.generatorUpdatable = {
                age: 0,
                delay: coreEngineConfig.access("perfomance.world_generator.delay"),
                surface_radius: coreEngineConfig.access("perfomance.world_generator.radius"),
                underground_radius: coreEngineConfig.access("perfomance.world_generator.underground_radius"),
                thread_optimization: coreEngineConfig.access("perfomance.world_generator.thread_optimization") && !coreEngineConfig.access("perfomance.run_on_main_thread"),
                generation_priority: coreEngineConfig.access("perfomance.world_generator.generation_thread_priority"),
                ticking_priority: TickingThread.priority,
                debug: coreEngineConfig.access("debug.log_generation_time_data"),
                debug_max_time: 0,
                update: function() {
                    if (!(0 < this.age++ % this.delay)) {
                        var a = Math.max(this.surface_radius, this.underground_radius),
                            b = 2 * a + 1,
                            c = this.age / this.delay % (b * b),
                            a = {
                                x: parseInt(c % b) - a,
                                z: parseInt(c / b) - a
                            },
                            b = {
                                x: Math.floor(getPlayerX() / 16 + .5),
                                z: Math.floor(getPlayerZ() / 16 + .5)
                            };
                        a.x += b.x;
                        a.z += b.z;
                        c = Player.getDimension();
                        if (this.debug) {
                            var d = CoreAPI.Debug.sysTime();
                            WorldGeneration.processChunk(a, b, c);
                            a = (CoreAPI.Debug.sysTime() - d) / 1E3;
                            a > this.debug_max_time && (this.debug_max_time = a, Logger.Log("Chunk Generation Took " + a + "s", "DEBUG"))
                        } else WorldGeneration.processChunk(a, b, c)
                    }
                }
            };
            UpdatableAPI.addUpdatable(this.generatorUpdatable)
        }
    },
    WorldGenerationUtils = {
        TERRAIN: {
            1: !0,
            2: !0,
            3: !0,
            7: !0,
            12: !0,
            13: !0,
            14: !0,
            15: !0,
            16: !0,
            21: !0,
            24: !0,
            56: !0,
            73: !0,
            82: !0,
            87: !0,
            88: !0,
            89: !0,
            110: !0,
            121: !0,
            243: !0
        },
        TRANSPARENT: {
            0: !0,
            8: !0,
            9: !0,
            10: !0,
            11: !0,
            18: !0,
            30: !0,
            31: !0,
            32: !0,
            37: !0,
            38: !0,
            39: !0,
            40: !0,
            78: !0,
            81: !0,
            83: !0,
            86: !0,
            106: !0
        },
        isTerrainBlock: function(a) {
            return this.TERRAIN[a] || !1
        },
        isTransparentBlock: function(a) {
            return this.TRANSPARENT[a] || !1
        },
        randomXZ: function(a, b) {
            return {
                x: parseInt(16 * (Math.random() + a)),
                z: parseInt(16 * (Math.random() + b))
            }
        },
        randomCoords: function(a, b, c, d) {
            c || (c = 0);
            d || (d = 128);
            d < c && (d = c);
            a = this.randomXZ(a, b);
            a.y = parseInt(Math.random() * (d - c) + c);
            return a
        },
        findSurface: function(a, b, c) {
            var d = getTile_origin(a, b, c),
                d = this.isTerrainBlock(d),
                e;
            for (e = d ? 1 : -1; this.isTerrainBlock(getTile_origin(a, b, c)) == d && 0 <= b;) b += e;
            d && b--;
            return {
                x: a,
                y: b,
                z: c
            }
        },
        findHighSurface: function(a, b) {
            return this.findSurface(a, 128, b)
        },
        findLowSurface: function(a, b) {
            return this.findSurface(a, 64, b)
        },
        __lockedReal: {
            id: 0,
            data: 0
        },
        lockInBlock: function(a, b, c, d) {
            this.__lockedReal = UnlimitedAPI.GetReal(a || 0, b || 0);
            a = this.__lockedReal.id;
            b = this.__lockedReal.data;
            this.setLockedBlock = "undefined" == c + "" ? function(c, d, g) {
                setTile_origin(c, d, g, a, b)
            } : d ? function(d, f, g) {
                getTile_origin(d, f, g) !=
                    c && setTile_origin(d, f, g, a, b)
            } : function(d, f, g) {
                getTile_origin(d, f, g) == c && setTile_origin(d, f, g, a, b)
            }
        },
        setLockedBlock: function(a, b, c) {
            setTile_origin(a, b, c, this.__lockedReal.id, this.__lockedReal.data)
        },
        genMinable: function(a, b, c, d) {
            d.ratio || (d.ratio = .125);
            var e = 0,
                f = 2 * (Math.random() - .5),
                g = 2 * (Math.random() - .5),
                h = 2 * (Math.random() - .5);
            for (this.lockInBlock(d.id, d.data, d.checkerTile, d.checkerMode); e < d.size;) {
                for (var k = d.size * d.ratio, m = -k; m <= k; m++)
                    for (var l = -k; l <= k; l++)
                        for (var n = -k; n <= k; n++) m * m + l * l + n * n <= k * k &&
                            this.setLockedBlock(a + m, b + l, c + n);
                a += k * (Math.random() - .5 + f) * .8;
                b += k * (Math.random() - .5 + g) * .8;
                c += k * (Math.random() - .5 + h) * .8;
                e += k
            }
        }
    };
try {
    ModPE.setItem(512, "__missing", 0, "placeholder", 1)
} catch (a) {
    ModPE.setItem(512, "stick", 0, "placeholder", 1), Logger.Log("unable to create item placeholder (id 512), because of: " + a, "ERROR")
}
Item.setProperties(512, {
    foil: !0
});
var IdentifierRegistry = {
        uniqueID: {
            item: 513,
            block: 8192,
            misc: 32768
        },
        data: {
            item: {},
            block: {},
            misc: {}
        },
        reversedData: {
            item: {},
            block: {},
            misc: {}
        },
        loadDataFromStatic: function(a) {
            for (var b in a) {
                this.data[b] || (this.data[b] = {});
                var c = a[b],
                    d;
                for (d in c) {
                    var e = c[d];
                    this.data[b][d] = parseInt(e);
                    this.reversedData[b][e] = d
                }
            }
        },
        genUniqueID: function(a, b) {
            if (this.data[b][a]) return StaticIDSource.registerNamedID(b, a, this.data[b][a]), this.data[b][a];
            for (var c = this.uniqueID[b]++; this.reversedData[b][c];) c = this.uniqueID[b]++;
            this.data[b][a] = c;
            this.reversedData[b][c] = a;
            StaticIDSource.registerNamedID(b, a, c);
            return c
        },
        genItemID: function(a) {
            return this.genUniqueID(a, "item")
        },
        genBlockID: function(a) {
            return this.genUniqueID(a, "block")
        },
        genMiscID: function(a) {
            return this.genUniqueID(a, "misc")
        },
        getNameByID: function(a) {
            return this.reversedData.block[a] || this.reversedData.item[a] || this.reversedData.misc[a] || null
        },
        addedInCreative: [],
        requireCreativeAdd: function(a, b) {
            var c = "__creative" + a + ":" + b;
            this.addedInCreative[c] || (Player.addItemCreativeInv(a,
                64, b), this.addedInCreative[c] = !0)
        }
    },
    StaticIDSource = {
        FILE: "games/com.mojang/mods/.staticids",
        oldData: {},
        currentData: {},
        PostRestart: function() {
            Callback.addCallback("PostLoaded", function() {
                modList && 0 < modList.length && (Callback.invokeCallback("PreRestart"), RestartBlocklauncher())
            })
        },
        LoadData: function() {
            this.oldData = FileTools.ReadJSON(this.FILE);
            this.currentData = {
                types: {},
                id: {},
                blocks: {}
            };
            this.oldData.types || (this.oldData.types = {});
            this.oldData.id || (this.oldData.id = {});
            this.oldData.blocks || (this.oldData.blocks = {});
            this.oldData.lock || (this.PostRestart(), this.oldData.types = {}, this.oldData.blocks = {});
            this.currentData.lock = !0;
            IdentifierRegistry.loadDataFromStatic(this.oldData.id);
            for (var a in this.oldData.types) {
                var b = parseInt(this.oldData.types[a]);
                if (1 > b || 255 < b) Logger.Log("special type '" + a + "' loaded with invalid id, all blocks on it will be recreated", "WARNING"), delete this.oldData.types[a]
            }
            for (a in this.oldData.types) this.specialTypeMap[this.oldData.types[a]] = a
        },
        SaveData: function() {
            FileTools.WriteJSON(this.FILE,
                this.currentData, !0);
            this.currentData.types || (this.currentData.types = {});
            this.currentData.id || (this.currentData.id = {});
            this.currentData.blocks || (this.currentData.blocks = {})
        },
        isBlockMatchesWithType: function(a, b) {
            for (var c in a.group)
                if (a.group[c].id != b) return !1;
            return !0
        },
        isBlockIdValid: function(a) {
            for (var b in a.group) {
                var c = parseInt(a.group[b].id);
                if (1 > c || 255 < c || UnlimitedAPI.isNativeBlock(c)) return !1
            }
            return !0
        },
        registerBlock: function(a, b, c) {
            if (this.oldData.blocks[a]) {
                var d = this.oldData.blocks[a];
                c &&
                    !this.isBlockMatchesWithType(d, c) ? (UnlimitedAPIAccess.RegisterBlock(a, b, c), Logger.Log("Some blocks on ID " + a + " do not match with block type " + c + ", recreating", "WARNING")) : this.isBlockIdValid(d) ? UnlimitedAPI.RegisterStaticBlockGroup(a, this.oldData.blocks[a].group || [], b) : (UnlimitedAPIAccess.RegisterBlock(a, b, c), Logger.Log("Some blocks on ID " + a + " has invalid saved real ID (conflicts with some native block, or out of range), recreating", "WARNING"))
            } else Callback.addCallback("PreBlocksDefined", function() {
                UnlimitedAPIAccess.RegisterBlock(a,
                    b, c)
            })
        },
        registerBlockGroup: function(a, b) {
            this.currentData.blocks[a] = {
                id: a,
                group: b
            }
        },
        registerNamedID: function(a, b, c) {
            this.currentData.id[a] || (this.currentData.id[a] = {});
            this.currentData.id[a][b] = c
        },
        specialTypeKeys: {},
        specialTypeMap: {},
        hasSpecialTypeForID: function(a) {
            return this.specialTypeMap[a]
        },
        getSpecialType: function(a) {
            return parseInt(this.oldData.types[a]) || null
        },
        registerSpecialType: function(a, b) {
            this.oldData.types[a] = b;
            this.currentData.types[a] = b;
            this.specialTypeMap[b] = a
        },
        genSpecialTypeKey: function(a) {
            a =
                JSON.stringify(a);
            this.specialTypeKeys[a] = !0;
            return a
        }
    };
StaticIDSource.LoadData();
Callback.addCallback("PostLoaded", function() {
    StaticIDSource.SaveData()
});
Callback.addCallback("BlockDefineComplete", function() {
    StaticIDSource.SaveData()
});
var UnlimitedAPI = {
        SpecifiedBlockData: [],
        PostedDefine: [],
        SetDefaultData: function(a) {
            a.base = 20;
            a.opaque = !1;
            a.rendertype = 0;
            a.renderlayer = BlockRenderLayer.alpha;
            a.destroytime = 1;
            a.redstoneconsumer = !0;
            a.lightopacity = 1;
            a.lightlevel = 0;
            a.explosionres = 2;
            a.color = [16777215]
        },
        GetBlockSpecial: function(a) {
            this.SpecifiedBlockData[a] || (this.SpecifiedBlockData[a] = {}, this.SetDefaultData(this.SpecifiedBlockData[a]));
            return this.SpecifiedBlockData[a]
        },
        SetBlockSpecial: function(a, b) {
            var c = this.GetBlockSpecial(a),
                d;
            for (d in b) c[d] =
                b[d]
        },
        SpecialBlockOffset: 255,
        GenerateSpecialBlock: function(a) {
            for (; Item.isValidItem(this.SpecialBlockOffset) || StaticIDSource.hasSpecialTypeForID(this.SpecialBlockOffset);) this.SpecialBlockOffset--;
            this.SetBlockSpecial(this.SpecialBlockOffset, a);
            return this.SpecialBlockOffset--
        },
        GenerateSpecialType: function(a, b) {
            if (!b || 1 > b) b = 1;
            var c = 255;
            for (var d = 0; d < b; d++) c = Math.min(c, this.GenerateSpecialBlock(a));
            return c
        },
        ExtendSpecialType: function(a) {
            a = this.GetBlockSpecial(a);
            return BlockRegistry.createSpecialType(a)
        },
        PostDefine: function(a, b, c, d) {
            this.GetBlockSpecial(a);
            this.PostedDefine[a] || (this.PostedDefine[a] = []);
            this.PostedDefine[a][b] = {
                name: c,
                texture: d
            }
        },
        DeleteDefine: function(a, b) {
            this.PostedDefine[a] && this.PostedDefine[a][b] && delete this.PostedDefine[a][b];
            this.NextFreeID = Math.min(parseInt(a), this.NextFreeID)
        },
        GetName: function(a, b) {
            var c = this.GetReal(a, b);
            return this.PostedDefine[c.id] && this.PostedDefine[c.id][c.data] ? Translation.translate(this.PostedDefine[c.id][c.data].name) : Item.getNameOrigin(a, b) + ""
        },
        ExecuteAllDefines: function() {
            var a = 0,
                b = 0,
                c = 0,
                d = [];
            coreEngineConfig && (coreEngineConfig.access("util.show_item_names") || coreEngineConfig.access("util.show_item_data_values"));
            for (var e in this.PostedDefine) {
                a++;
                for (var f = [], g = this.GetBlockSpecial(e), h = 0; 16 > h; h++)
                    for (var k = 0; 6 > k; k++) f[6 * h + k] = ["__missing", 0];
                for (var m in this.PostedDefine[e]) {
                    var l = this.PostedDefine[e][m];
                    for (k in l.texture) f[6 * parseInt(m) + parseInt(k)] = l.texture[k];
                    c++
                }
                if (0 < e && 256 > e) try {
                    Block.defineBlock(e, "", f, g.base, g.opaque, g.rendertype)
                } catch (n) {
                    for (m in Logger.Log("failed to add block with id " +
                            e + "(" + n.message + "), recreating with missing texture...", "ERROR"), Block.defineBlock(e, "", [
                            ["__missing", 0]
                        ], g.base, g.opaque, g.rendertype), this.PostedDefine[e]) d.push(this.PostedDefine[e][m].name)
                } else {
                    for (m in this.PostedDefine[e]) d.push(this.PostedDefine[e][m].name);
                    Logger.Log("failed to add block with id " + e + ": block id is out of range, maybe id limit was extended", "ERROR")
                }
                Block.setRenderLayer(e, g.renderlayer);
                Block.setLightOpacity(e, g.lightopacity);
                Block.setDestroyTime(e, g.destroytime);
                Block.setLightLevel(e,
                    g.lightlevel);
                Block.setExplosionResistance(e, g.explosionres);
                Block.setRedstoneConsumer(e, g.redstoneconsumer);
                Block.setColor(e, g.color);
                for (m = 0; 16 > m; m++)(l = this.PostedDefine[e][m]) && l.shape ? Block.setShape_origin(e, l.shape[0], l.shape[1], l.shape[2], l.shape[3], l.shape[4], l.shape[5], m) : Block.setShape_origin(e, 0, 0, 0, 1, 1, 1, m)
            }
            this.isDefined = !0;
            for (h in this.BlockGroups) b++;
            Logger.Log("All blocks defined", "UNLIMITED");
            Logger.Log("-- total blocks defined: " + b, "UNLIMITED");
            Logger.Log("-- total block variations defined: " +
                (c - d.length), "UNLIMITED");
            Logger.Log("-- real blocks defined: " + a, "UNLIMITED");
            Logger.Log("-- block define skipped: " + d.length + " (" + (0 < d.length ? "some errors occured" : "ok") + ")", "UNLIMITED");
            0 < d.length && Logger.Log("-- skipped block names: " + d.join(", "), "ERROR")
        },
        NextFreeID: 25,
        isNativeBlock: function(a) {
            return !Item.isValidItem(a, 0) || "" == Item.getName(a) || this.PostedDefine[a] ? !1 : !0
        },
        FindFreePlaceForBlock: function() {
            for (var a = this.NextFreeID, b = 0; 1024 > a;) {
                if (!this.isNativeBlock(a))
                    if (this.PostedDefine[a]) {
                        for (var b = -1, c = 0; 16 > c; c++)
                            if (!this.PostedDefine[a][c]) {
                                b = c;
                                break
                            }
                        if (-1 < b) break;
                        b = 0
                    } else {
                        b = 0;
                        break
                    }
                a++
            }
            this.NextFreeID = a;
            return {
                id: a,
                data: b
            }
        },
        BlockGroups: [],
        UIDbyReal: [],
        RealByUID: [],
        ClearBlockGroup: function(a) {
            var b = this.BlockGroups[a],
                c;
            for (c in b) {
                var d = b[c];
                d && (this.DeleteDefine(d.id, d.data), delete this.UIDbyReal[d.id + ":" + d.data], delete this.RealByUID[a + ":" + c])
            }
            delete this.BlockGroups[a]
        },
        RegisterBlockGroup: function(a, b, c) {
            this.NextUniqueID = Math.max(a + 1, this.NextUniqueID);
            var d = UnlimitedAPI.NextFreeID;
            0 <
                c && (UnlimitedAPI.NextFreeID = c);
            this.BlockGroups[a] && this.ClearBlockGroup(a);
            var e = [],
                f;
            for (f in b) {
                var g = this.FindFreePlaceForBlock();
                0 < c && g.id != c && (UnlimitedAPI.NextFreeID = this.ExtendSpecialType(c), g = this.FindFreePlaceForBlock(), Logger.Log("block variation limit reached, special block type extended: " + c + " -> " + UnlimitedAPI.NextFreeID, "UNLIMITED"), c = UnlimitedAPI.NextFreeID);
                this.PostDefine(g.id, g.data, b[f].name, b[f].texture);
                e.push(g);
                this.UIDbyReal[g.id + ":" + g.data] = {
                    id: a,
                    data: f
                };
                this.RealByUID[a +
                    ":" + f] = g
            }
            this.BlockGroups[a] = e;
            StaticIDSource.registerBlockGroup(a, e);
            UnlimitedAPI.NextFreeID = d
        },
        RegisterStaticBlockGroup: function(a, b, c) {
            this.BlockGroups[a] && this.ClearBlockGroup(a);
            var d = [],
                e;
            for (e in c) {
                var f = b[e] || this.FindFreePlaceForBlock();
                this.PostDefine(f.id, f.data, c[e].name, c[e].texture);
                d.push(f);
                this.UIDbyReal[f.id + ":" + f.data] = {
                    id: a,
                    data: e
                };
                this.RealByUID[a + ":" + e] = f
            }
            this.BlockGroups[a] = d;
            StaticIDSource.registerBlockGroup(a, d)
        },
        SetShape: function(a, b, c) {
            this.isDefined && Block.setShape_origin(a,
                c[0], c[1], c[2], c[3], c[4], c[5], b);
            this.PostedDefine[a] && this.PostedDefine[a][b] && (this.PostedDefine[a][b].shape = c)
        },
        GetReal: function(a, b) {
            return UnlimitedAPI.BlockGroups[a] ? UnlimitedAPI.BlockGroups[a][Math.min(b, UnlimitedAPI.BlockGroups[a].length - 1)] || {
                id: a,
                data: b
            } : {
                id: a,
                data: b
            }
        },
        GetUID: function(a, b) {
            return UnlimitedAPI.UIDbyReal[a + ":" + b] || {
                id: a,
                data: b
            }
        }
    },
    __UnlimitedAPI_GetReal = UnlimitedAPI.GetReal,
    __UnlimitedAPI_GetUID = UnlimitedAPI.GetUID,
    UnlimitedAPIAccess = {
        RegisterBlock: function(a, b, c) {
            UnlimitedAPI.RegisterBlockGroup(a,
                b, c)
        },
        getFullTile: function(a, b, c) {
            return __UnlimitedAPI_GetUID(getTile_origin(a, b, c), Level.getData_origin(a, b, c))
        },
        setFullTile: function(a, b, c, d, e) {
            d = __UnlimitedAPI_GetReal(d || 0, e || 0);
            setTile_origin(a, b, c, d.id, d.data)
        },
        getCarriedItem: function(a) {
            var b = getCarriedItem_origin(),
                c = Player.getCarriedItemData_origin(),
                b = __UnlimitedAPI_GetUID(b, c),
                b = {
                    id: b.id,
                    data: b.data,
                    count: Player.getCarriedItemCount()
                };
            a && (b.enchant = Player.getEnchantments(Player.getSelectedSlotId()));
            return b
        },
        setCarriedItem: function(a,
            b, c, d) {
            b || (b = 0);
            if (!d || 0 > d) d = 0;
            if (!c || 1 > c) b = d = c = 0;
            b = __UnlimitedAPI_GetReal(b, d);
            Entity.setCarriedItem_origin(a, b.id, c, b.data)
        },
        setPlayerCarriedItem: function(a, b, c, d) {
            this.setCarriedItem(getPlayerEnt(), a, b, c);
            if (d) {
                a = Player.getSelectedSlotId();
                for (var e in d) b = d[e], Player.enchant(a, b.type, b.level)
            }
        },
        delayedCreativeItems: [],
        addCreativeItem: function(a, b) {
            var c = __UnlimitedAPI_GetReal(a || 0, b || 0);
            try {
                Player.addItemCreative_origin(c.id, Item.getMaxStackSize(c.id), c.data)
            } catch (d) {
                this.delayedCreativeItems.push({
                    id: a,
                    data: b
                }), Logger.Log("creative item not found, it will be added later, real=" + [c.id, c.data] + ", uid=" + [a, b] + ", name=" + IdentifierRegistry.getNameByID(a), "ITEM")
            }
        },
        addListToCreative: function(a) {
            for (var b in a) this.addCreativeItem(a[b], 0)
        },
        addDelayedCreativeItems: function() {
            for (var a in this.delayedCreativeItems) {
                var b = this.delayedCreativeItems[a];
                this.addCreativeItem(b.id, b.data)
            }
            this.delayedCreativeItems = []
        }
    };
Callback.addCallback("BlocksDefined", function() {
    UnlimitedAPI.ExecuteAllDefines();
    Callback.invokeCallback("BlockDefineComplete");
    UnlimitedAPIAccess.addDelayedCreativeItems()
});
var setTile_origin = setTile;
setTile = function(a, b, c, d, e) {
    d = __UnlimitedAPI_GetReal(d || 0, e || 0);
    setTile_origin(a, b, c, d.id, d.data)
};
Level.setTile = setTile;
var getTile_origin = getTile;
getTile = function(a, b, c) {
    return __UnlimitedAPI_GetUID(getTile_origin(a, b, c), Level.getData_origin(a, b, c)).id
};
Level.getTile = getTile;
Level.getData_origin = Level.getData;
Level.getData = function(a, b, c) {
    return __UnlimitedAPI_GetUID(getTile_origin(a, b, c), Level.getData_origin(a, b, c)).data
};
var getCarriedItem_origin = getCarriedItem;
getCarriedItem = function() {
    return UnlimitedAPIAccess.getCarriedItem().id
};
Player.getCarriedItem = getCarriedItem;
Player.getCarriedItemData_origin = Player.getCarriedItemData;
Player.getCarriedItemData = function() {
    return UnlimitedAPIAccess.getCarriedItem().data
};
Entity.setCarriedItem_origin = Entity.setCarriedItem;
Entity.setCarriedItem = function(a, b, c, d) {
    UnlimitedAPIAccess.setCarriedItem(a, b, c, d)
};
var addItemInv_origin = addItemInventory;
addItemInventory = function(a, b, c) {
    a = __UnlimitedAPI_GetReal(a, c || 0);
    addItemInv_origin(a.id, b, a.data)
};
Player.addItemInventory = addItemInventory;
Player.addItemCreative_origin = Player.addItemCreativeInv;
Player.addItemCreativeInv = function(a, b, c) {
    UnlimitedAPIAccess.addCreativeItem(a, c)
};
Item.addShapedRecipe_origin = Item.addShapedRecipe;
Item.addShapedRecipe = function(a, b, c, d, e) {
    try {
        for (var f in e)
            if (f = parseInt(f), 0 == f % 3) {
                var g = __UnlimitedAPI_GetReal(e[f + 1], e[f + 2]);
                e[f + 1] = g.id;
                e[f + 2] = g.data
            }
        var h = __UnlimitedAPI_GetReal(a, c);
        Item.addShapedRecipe_origin(h.id, b, h.data, d, e)
    } catch (k) {
        print("failed to add recipe for " + [h.id, h.data] + " UID is " + [a, c])
    }
};
Block.setShape_origin = Block.setShape;
Block.setShape = function(a, b, c, d, e, f, g, h) {
    if ("undefined" == typeof h) {
        h = UnlimitedAPI.BlockGroups[a];
        for (var k in h) h = __UnlimitedAPI_GetReal(a, k), UnlimitedAPI.SetShape(h.id, h.data, [b, c, d, e, f, g])
    } else h = __UnlimitedAPI_GetReal(a, h), UnlimitedAPI.SetShape(h.id, h.data, [b, c, d, e, f, g])
};
Level.dropItem_origin = Level.dropItem;
Level.dropItem = function(a, b, c, d, e, f, g) {
    e = __UnlimitedAPI_GetReal(e, g);
    d = Level.dropItem_origin(a, b, c, d, e.id, f, e.data);
    setPosition(d, a, b, c);
    return d
};
Player.getInventorySlot_origin = Player.getInventorySlot;
Player.getInventorySlot = function(a) {
    return __UnlimitedAPI_GetUID(Player.getInventorySlot_origin(a), Player.getInventorySlotData_origin(a)).id
};
Player.getInventorySlotData_origin = Player.getInventorySlotData;
Player.getInventorySlotData = function(a) {
    return __UnlimitedAPI_GetUID(Player.getInventorySlot_origin(a), Player.getInventorySlotData_origin(a)).data
};
Player.setInventorySlot_origin = Player.setInventorySlot;
Player.setInventorySlot = function(a, b, c, d) {
    b = __UnlimitedAPI_GetReal(b, d);
    Player.setInventorySlot_origin(a, Math.max(b.id, 0), c, b.data)
};
Entity.getItemEntityId_origin = Entity.getItemEntityId;
Entity.getItemEntityId = function(a) {
    return __UnlimitedAPI_GetUID(Entity.getItemEntityId_origin(a), Entity.getItemEntityData_origin(a)).id
};
Entity.getItemEntityData_origin = Entity.getItemEntityData;
Entity.getItemEntityData = function(a) {
    return __UnlimitedAPI_GetUID(Entity.getItemEntityId_origin(a), Entity.getItemEntityData_origin(a)).data
};
Level.getChestSlot_origin = Level.getChestSlot;
Level.getChestSlot = function(a, b, c, d) {
    return __UnlimitedAPI_GetUID(Level.getChestSlot_origin(a, b, c, d), Level.getChestSlotData_origin(a, b, c, d)).id
};
Level.getChestSlotData_origin = Level.getChestSlotData;
Level.getChestSlotData = function(a, b, c, d) {
    return __UnlimitedAPI_GetUID(Level.getChestSlot_origin(a, b, c, d), Level.getChestSlotData_origin(a, b, c, d)).data
};
Level.setChestSlot_origin = Level.setChestSlot;
Level.setChestSlot = function(a, b, c, d, e, f, g) {
    e = __UnlimitedAPI_GetReal(e, f);
    Level.setChestSlot_origin(a, b, c, d, Math.max(e.id, 0), e.data, g)
};
Level.getFurnaceSlot_origin = Level.getFurnaceSlot;
Level.getFurnaceSlot = function(a, b, c, d) {
    return __UnlimitedAPI_GetUID(Level.getFurnaceSlot_origin(a, b, c, d), Level.getFurnaceSlotData_origin(a, b, c, d)).id
};
Level.getFurnaceSlotData_origin = Level.getFurnaceSlotData;
Level.getFurnaceSlotData = function(a, b, c, d) {
    return __UnlimitedAPI_GetUID(Level.getFurnaceSlot_origin(a, b, c, d), Level.getFurnaceSlotData_origin(a, b, c, d)).data
};
Level.setFurnaceSlot_origin = Level.setFurnaceSlot;
Level.setFurnaceSlot = function(a, b, c, d, e, f, g) {
    e = __UnlimitedAPI_GetReal(e, f);
    Level.setFurnaceSlot_origin(a, b, c, d, Math.max(e.id, 0), e.data, g)
};
Player.getPointedBlockId_origin = Player.getPointedBlockId;
Player.getPointedBlockId = function() {
    return __UnlimitedAPI_GetUID(Player.getPointedBlockId_origin(), Player.getPointedBlockData_origin()).id
};
Player.getPointedBlockData_origin = Player.getPointedBlockData;
Player.getPointedBlockData = function() {
    return __UnlimitedAPI_GetUID(Player.getPointedBlockId_origin(), Player.getPointedBlockData_origin()).data
};
Item.getNameOrigin = Item.getName;
Item.getName = function(a, b, c) {
    try {
        return Item.getNameOrigin(a, b, c)
    } catch (d) {
        return null
    }
};
Item.isValidItemOrigin = Item.isValidItem;
Item.isValidItem = function(a, b) {
    if (95 == a || 160 == a) return !0;
    if (0 > a || 256 < a || !Item.isValidItemOrigin(a, b)) return !1;
    var c = Item.getName(a, 0, !0);
    return !c || -1 != c.indexOf("Missing") || parseInt(c.split(".")[1]) + 1 ? !1 : !0
};
var BLOCK_BASE_PROTOTYPE = {
        __validBlockTypes: {
            createBlock: !0,
            createBlockWithRotation: !0
        },
        __define: function(a) {
            var b = this.getVariations(a);
            b || (Logger.Log("block prototype " + this.stringID + " has no variations, it will be replaced with missing block (1 variation)", "WARNING"), b = {
                name: "noname:" + this.stringID,
                texture: [
                    ["__missing", 0]
                ]
            });
            a = this.getSpecialType(a);
            this.__validBlockTypes[this.type] || (Logger.Log("block prototype " + this.stringID + " has invalid type " + this.type + " it will be replaced with default",
                "WARNING"), this.type = "createBlock");
            BlockRegistry[this.type](this.stringID, b, a);
            if (!this.isDefined) {
                var c = this;
                this.getDrop && BlockRegistry.registerDropFunction(this.stringID, function(a, b, f, g, h) {
                    return c.getDrop(a, b, f, g, h)
                });
                this.onPlaced && BlockRegistry.registerDropFunction(this.stringID, function(a, b, f) {
                    return c.onPlaced(a, b, f)
                })
            }
            this.isDefined = !0
        },
        __describe: function(a) {
            if (this.isDefined) {
                var b = this.getMaterial(a);
                null != b && ToolAPI.registerBlockMaterial(this.id, b);
                a = this.getDestroyLevel(a);
                0 < a && (b ||
                    Logger.Log("block prototype " + this.stringID + " defining digging level with no material, create getMaterial() method", "WARNING"), this.getDrop ? ToolAPI.registerBlockDiggingLevel(this.id, a) : Block.setDestroyLevelForID(this.id, level));
                b = this.getShape() || [0, 0, 0, 1, 1, 1];
                6 <= b.length ? BlockRegistry.setBlockShape(this.id, {
                    x: b[0],
                    y: b[1],
                    z: b[2]
                }, {
                    x: b[3],
                    y: b[4],
                    z: b[5]
                }) : Logger.Log("block prototype " + this.stringID + " has invalid block shape " + b, "WARNING")
            } else Logger.Log("block prototype cannot call __describe method: block is not defined",
                "ERROR")
        },
        init: function() {},
        getVariations: function(a) {
            return null
        },
        getSpecialType: function(a) {
            return null
        },
        getCategory: function(a) {
            return null
        },
        getEnchant: function(a) {
            return null
        },
        getProperties: function(a) {
            return null
        },
        isStackedByData: function(a) {
            return null
        },
        isEnchanted: function(a) {
            return null
        },
        getMaterial: function(a) {
            return null
        },
        getDestroyLevel: function(a) {
            return 0
        },
        getShape: function(a) {
            return null
        },
        getDrop: null,
        onPlaced: null,
        onItemUsed: null
    },
    BlockRegistry = {
        idSource: IdentifierRegistry.data.block,
        dropFunctions: {},
        DEFAULT_ICON_RESOLUTION: 96,
        setGuiIconParams: function(a, b) {
            this.DEFAULT_ICON_RESOLUTION = a ? Math.max(16, b || 0) : -1
        },
        createBlock: function(a, b, c) {
            var d = this.idSource[a];
            if (!d) return Logger.Log("Invalid block namedID: " + a, "ERROR"), !1;
            for (var e in b) {
                var f = b[e];
                f.texture || (f.texture = []);
                for (; 6 > f.texture.length;) f.texture.push(f.texture[f.texture.length - 1] || ["__missing", 0])
            }
            StaticIDSource.registerBlock(d, b, c);
            for (e in b) b[e].inCreative && IdentifierRegistry.requireCreativeAdd(d, e);
            if (-1 != this.DEFAULT_ICON_RESOLUTION)
                for (e in b)
                    if (c =
                        GuiUtils.genBlockTexture(b[e].texture, null, this.DEFAULT_ICON_RESOLUTION)) f = "__auto_" + a + ":" + e, GuiAPI.addItemOverride(d, e, f), GuiAPI.registerBitmap(f, c);
            return !0
        },
        createBlockWithRotation: function(a, b, c) {
            var d = this.idSource[a];
            if (!d) return Logger.Log("Invalid block namedID: " + a, "ERROR"), !1;
            var e = [],
                f;
            for (f in b) {
                var g = b[f],
                    h = g.texture,
                    h = [
                        [h[0], h[1], h[2], h[3], h[4], h[5]],
                        [h[0], h[1], h[3], h[2], h[5], h[4]],
                        [h[0], h[1], h[5], h[4], h[2], h[3]],
                        [h[0], h[1], h[4], h[5], h[3], h[2]]
                    ],
                    k;
                for (k in h) e.push({
                    name: g.name,
                    texture: h[k],
                    inCreative: g.inCreative && 0 == k
                })
            }
            this.createBlock(a, e, c);
            this.registerPlaceFunction(a, function(a, b, c) {
                for (c = Math.floor((Entity.getYaw(getPlayerEnt()) - 45) / 90); 0 > c;) c += 4;
                for (; 3 < c;) c -= 4;
                c = {
                    0: 2,
                    1: 0,
                    2: 3,
                    3: 1
                }[c];
                canTileBeReplaced(getTile(a.relative.x, a.relative.y, a.relative.z)) && setTile(a.relative.x, a.relative.y, a.relative.z, b.id, 4 * parseInt(b.data / 4) + c);
                return a.relative
            });
            this.registerDropFunction(a, function(a, b, c) {
                return [
                    [d, 1, 4 * parseInt(c / 4)]
                ]
            })
        },
        isNativeTile: function(a) {
            return null == IdentifierRegistry.getNameByID(a)
        },
        registerDropFunctionForID: function(a, b, c) {
            this.dropFunctions[a] = b;
            c && ToolAPI.registerBlockDiggingLevel(a, c);
            return !0
        },
        registerDropFunction: function(a, b, c) {
            var d = this.idSource[a];
            return d ? this.registerDropFunctionForID(d, b, c) : (Logger.Log("Invalid block namedID: " + a, "ERROR"), !1)
        },
        defaultDropFunction: function(a, b, c, d) {
            return this.isNativeTile(b) ? null : [
                [b, 1, c]
            ]
        },
        getDropFunction: function(a) {
            return this.dropFunctions[a] || this.defaultDropFunction
        },
        setDestroyLevelForID: function(a, b) {
            this.registerDropFunctionForID(a,
                function(a, d, e, f) {
                    if (BlockRegistry.isNativeTile(d) && 0 >= b) return null;
                    if (f >= b) return [
                        [d, 1, e]
                    ]
                }, b)
        },
        setDestroyLevel: function(a, b) {
            var c = this.idSource[a];
            return c ? this.setDestroyLevelForID(c, b) : (Logger.Log("Invalid block namedID: " + a, "ERROR"), !1)
        },
        onBlockDestroyed: function(a, b) {
            var c = PlayerAPI.getCarriedItem(!0),
                d = this.getBlockDropViaItem(b, c, a);
            if (null != d) {
                Level.destroyBlock(a.x, a.y, a.z);
                for (var e in d) Level.dropItem(a.x + .5, a.y + .5, a.z + .5, 0, d[e][0], d[e][1], d[e][2])
            } else ToolAPI.needDamagableItemFix &&
                512 < c.id && (c.data = Math.max(0, c.data - 2), PlayerAPI.setCarriedItem(c.id, c.count, c.data, c.enchant, c.name))
        },
        getBlockDropViaItem: function(a, b, c) {
            var d = ToolAPI.getEnchantExtraData(b.enchant),
                e = ToolAPI.getToolData(b.id);
            this.__func = this.getDropFunction(a.id);
            e && e.modifyEnchant && e.modifyEnchant(d, b, c, a);
            return this.__func(c, a.id, a.data, ToolAPI.getToolLevelViaBlock(b.id, a.id), d)
        },
        placeFuncs: [],
        registerPlaceFunction: function(a, b) {
            var c = this.idSource[a];
            if (!c) return Logger.Log("Invalid block namedID: " + a, "ERROR"), !1;
            this.registerPlaceFunctionForID(c, b)
        },
        registerPlaceFunctionForID: function(a, b) {
            this.placeFuncs[a] = b
        },
        getPlaceFunc: function(a) {
            return this.placeFuncs[a]
        },
        setBlockShape: function(a, b, c, d) {
            UnlimitedAPI.isDefined ? Block.setShape(a, b.x, b.y, b.z, c.x, c.y, c.z, d) : Callback.addCallback("PostLoaded", function() {
                Block.setShape(a, b.x, b.y, b.z, c.x, c.y, c.z, d)
            })
        },
        setShape: function(a, b, c, d, e, f, g, h) {
            this.setBlockShape(a, {
                x: b,
                y: c,
                z: d
            }, {
                x: e,
                y: f,
                z: g
            }, h)
        },
        createSpecialType: function(a, b) {
            var c = b || StaticIDSource.genSpecialTypeKey(a),
                d = StaticIDSource.getSpecialType(c);
            d ? UnlimitedAPI.SetBlockSpecial(d, a) : d = UnlimitedAPI.GenerateSpecialType(a, 1);
            StaticIDSource.registerSpecialType(c, d);
            return d
        },
        TYPE_BASE: "createBlock",
        TYPE_ROTATION: "createBlockWithRotation",
        setPrototype: function(a, b) {
            var c = IdentifierRegistry.genBlockID(a),
                d;
            for (d in BLOCK_BASE_PROTOTYPE) b[d] || (b[d] = BLOCK_BASE_PROTOTYPE[d]);
            b.id = c;
            b.stringID = a;
            b.__define(null);
            b.__describe(null);
            b.init()
        }
    };
Callback.addCallback("DestroyBlock", function(a, b) {
    BlockRegistry.onBlockDestroyed(a, b)
});
var ITEM_BASE_PROTOTYPE = {
        __validItemTypes: {
            createItem: !0,
            createFoodItem: !0,
            createArmorItem: !0,
            createThrowableItem: !0
        },
        __define: function(a) {
            var b = this.getName(a);
            b || (Logger.Log("item prototype " + this.stringID + " has no name", "WARNING"), b = "noname:" + this.stringID);
            var c = this.getTexture(a);
            c || (Logger.Log("item prototype " + this.stringID + " has no texture, it will be replaced with missing icon", "WARNING"), c = {
                name: "__missing"
            });
            a = this.getDefineParams(a);
            this.__validItemTypes[this.type] || (Logger.Log("item prototype " +
                this.stringID + " has invalid type " + this.type + " it will be replaced with default", "WARNING"), this.type = "createItem");
            ItemRegistry[this.type](this.stringID, b, c, a);
            if (!this.isDefined) {
                var d = this;
                ItemRegistry.registerUseFunction(this.stringID, function(a, b, c) {
                    d.onUsed(a, b, c)
                });
                ItemRegistry.registerThrowableFunction(this.stringID, function(a, b, c) {
                    d.onThrowableImpact(a, b, c)
                })
            }
            this.isDefined = !0
        },
        __describe: function(a) {
            if (this.isDefined) {
                var b = this.getMaxDamage(a);
                null != b && ItemRegistry.setMaxDamage(this.id,
                    b);
                b = this.getCategory(a);
                null != b && ItemRegistry.setCategory(this.id, b);
                b = this.getEnchant(a);
                null != b && ItemRegistry.setEnchantType(this.id, b.type, b.value);
                b = this.getUseAnimation(a);
                null != b && ItemRegistry.setUseAnimation(this.id, b);
                if (b = this.getProperties(a)) b.foil = this.isEnchanted(a), ItemRegistry.setProperties(this.id, b);
                b = this.isToolRender(a);
                null != b && ItemRegistry.setToolRender(this.id, b);
                b = this.isStackedByData(a);
                null != b && ItemRegistry.setStackedByData(this.id, b);
                b = this.getArmorFuncs(a);
                null != b && ArmorRegistry.registerFuncsForID(this.id,
                    b);
                var b = this.getToolMaterial(a),
                    c = this.getToolPrototype(a);
                a = this.getToolTarget(a);
                null != b && null != c && null != a && ToolAPI.registerTool(this.id, b, a, c)
            } else Logger.Log("item prototype cannot call __describe method: item is not defined", "ERROR")
        },
        init: function() {},
        getName: function(a) {
            return null
        },
        getTexture: function(a) {
            return null
        },
        getDefineParams: function(a) {
            return null
        },
        getMaxDamage: function(a) {
            return null
        },
        getCategory: function(a) {
            return null
        },
        getEnchant: function(a) {
            return null
        },
        getUseAnimation: function(a) {
            return null
        },
        getProperties: function(a) {
            return null
        },
        isToolRender: function(a) {
            return null
        },
        isStackedByData: function(a) {
            return null
        },
        isEnchanted: function(a) {
            return null
        },
        getToolMaterial: function() {
            return null
        },
        getToolTarget: function() {
            return null
        },
        getToolPrototype: function() {
            return null
        },
        getArmorFuncs: function() {
            return null
        },
        onUsed: function(a, b, c) {},
        onTick: function(a) {},
        onThrowableImpact: function(a, b, c) {}
    },
    ItemRegistry = {
        idSource: IdentifierRegistry.data.item,
        useFunctions: {},
        throwableFunctions: {},
        createItem: function(a,
            b, c, d) {
            d || (d = {});
            d.stack = d.stack || 64;
            var e = this.idSource[a];
            if (!e) return Logger.Log("Invalid item namedID: " + a, "ERROR"), !1;
            ItemIconSource.addOverride(e + "", c.name + "_" + (c.meta || 0));
            try {
                ModPE.setItem(e, c.name, c.meta || 0, b, d.stack)
            } catch (f) {
                Logger.Log("failed to add item with id " + a + "(" + f + "), recreating with missing texture...", "ERROR"), ModPE.setItem(e, "__missing", 0, b, d.stack)
            }
            d.isTech || IdentifierRegistry.requireCreativeAdd(e, 0);
            return !0
        },
        createFoodItem: function(a, b, c, d) {
            d || (d = {});
            d.stack = d.stack || 64;
            d.food = d.food || 1;
            var e = this.idSource[a];
            if (!e) return Logger.Log("Invalid item namedID: " + a, "ERROR"), !1;
            ItemIconSource.addOverride(e + "", c.name + "_" + (c.meta || 0));
            try {
                ModPE.setFoodItem(e, c.name, c.meta || 0, d.food, b, d.stack)
            } catch (f) {
                Logger.Log("failed to add item with id " + a + "(" + f + "), recreating with missing texture...", "ERROR"), ModPE.setFoodItem(e, "__missing", 0, d.food, b, d.stack)
            }
            d.isTech || IdentifierRegistry.requireCreativeAdd(e, 0);
            return !0
        },
        createFuelItem: function(a, b, c, d) {
            Logger.Log("creating fuel item for on " +
                a + ": method deprecated ", "ERROR");
            d || (d = {});
            d.stack = d.stack || 64;
            d.fuel = d.fuel || 1;
            var e = this.idSource[a];
            if (!e) return Logger.Log("Invalid item namedID: " + a, "ERROR"), !1;
            ItemIconSource.addOverride(e + "", c.name + "_" + (c.meta || 0));
            try {
                ModPE.setFoodItem(e, c.name, c.meta || 0, d.food, b, d.stack)
            } catch (f) {
                Logger.Log("failed to add item with id " + a + "(" + f + "), recreating with missing texture...", "ERROR"), ModPE.setFoodItem(e, "__missing", 0, d.food, b, d.stack)
            }
            d.isTech || IdentifierRegistry.requireCreativeAdd(e, 0);
            return !0
        },
        createArmorItem: function(a, b, c, d) {
            var e = {
                helmet: {
                    id: ArmorType.helmet
                },
                chestplate: {
                    id: ArmorType.chestplate
                },
                leggings: {
                    id: ArmorType.leggings
                },
                boots: {
                    id: ArmorType.boots
                }
            };
            d || (d = {});
            d.stack = d.stack || 64;
            d.durability = d.durability || 1;
            d.armor = d.armor || 0;
            d.texture = d.texture || "armor.iron_1";
            if (e[d.type]) {
                var e = e[d.type].id,
                    f = this.idSource[a];
                if (!f) return Logger.Log("Invalid item namedID: " + a, "ERROR"), !1;
                ItemIconSource.addOverride(f + "", c.name + "_" + (c.meta || 0));
                try {
                    Item.defineArmor(f, c.name, c.meta || 0, b, d.texture,
                        d.armor, d.durability, e)
                } catch (g) {
                    Logger.Log("failed to add item with id " + a + "(" + g + "), recreating with missing texture...", "ERROR"), Item.defineArmor(f, "__missing", 0, b, d.texture, d.armor, d.durability, e)
                }
                d.isTech || IdentifierRegistry.requireCreativeAdd(f, 0);
                return !0
            }
            Logger.Log("Invalid armor type for item " + a + ": " + d.type + ',use: "helmet", "chestplate", "leggings", "boots"', "ERROR")
        },
        createThrowableItem: function(a, b, c, d) {
            d || (d = {});
            d.stack = d.stack || 64;
            var e = this.idSource[a];
            if (!e) return Logger.Log("Invalid item namedID: " +
                a, "ERROR"), !1;
            ItemIconSource.addOverride(e + "", c.name + "_" + (c.meta || 0));
            Item.__defineMethod = Item.defineThrowable;
            Item.__defineMethod || (Logger.Log("item " + a + " cannot be defined as throwable because of old version of mcpe", "WARNING"), Item.__defineMethod = ModPE.setItem);
            try {
                Item.__defineMethod(e, c.name, c.meta || 0, b, d.stack)
            } catch (f) {
                Logger.Log("failed to add item with id " + a + "(" + f + "), recreating with missing texture...", "ERROR"), Item.__defineMethod(e, "__missing", 0, b, d.stack)
            }
            d.isTech || IdentifierRegistry.requireCreativeAdd(e,
                0);
            return !0
        },
        isNativeItem: function(a) {
            return null == IdentifierRegistry.getNameByID(a)
        },
        getMaxDamage: function(a) {
            return 4096 < a ? 0 : Item.getMaxDamage(a)
        },
        getMaxStack: function(a) {
            return 4096 < a ? 64 : Item.getMaxStackSize(a)
        },
        getCustomThrowableRenderType: function(a) {
            return Item.getCustomThrowableRenderType(a)
        },
        getName: function(a, b, c) {
            return UnlimitedAPI.GetName(a, b)
        },
        getTextureCoords: function(a, b) {
            return Item.getTextureCoords(a, b)
        },
        getUseAnimation: function(a) {
            return Item.getUseAnimation(a)
        },
        isValid: function(a,
            b) {
            return Item.isValidItem(a, b || 0)
        },
        describeItem: function(a, b) {
            this.setCategory(a, b.category || 0);
            this.setToolRender(a, b.toolRender);
            this.setMaxDamage(a, b.maxDamage || 0);
            this.setStackedByData(a, b.stackByData);
            this.setUseAnimation(a, b.useAnimation);
            b.properties && this.setProperties(a, b.properties);
            b.enchant && this.setEnchantType(a, b.enchant.type, b.enchant.value)
        },
        setCategory: function(a, b) {
            Item.setCategory(a, b)
        },
        setEnchantType: function(a, b, c) {
            Item.setEnchantType(a, b, c)
        },
        setToolRender: function(a, b) {
            Item.setHandEquipped(a,
                b)
        },
        setMaxDamage: function(a, b) {
            Item.setMaxDamage(a, b)
        },
        setStackedByData: function(a, b) {
            Item.setStackedByData(a, b)
        },
        setProperties: function(a, b) {
            Item.setProperties(a, b)
        },
        setUseAnimation: function(a, b) {
            Item.setUseAnimation(a, b || 0)
        },
        registerUseFunctionForID: function(a, b) {
            this.useFunctions[a] = b;
            return !0
        },
        registerUseFunction: function(a, b) {
            var c = this.idSource[a];
            return c ? this.registerUseFunctionForID(c, b) : (Logger.Log("Invalid item namedID: " + a, "ERROR"), !1)
        },
        onItemUsed: function(a, b, c) {
            (this.__func = this.useFunctions[b.id]) &&
            this.__func(a, b, c)
        },
        registerThrowableFunctionForID: function(a, b) {
            this.throwableFunctions[a] = b;
            return !0
        },
        registerThrowableFunction: function(a, b) {
            var c = this.idSource[a];
            return c ? this.registerThrowableFunctionForID(c, b) : (Logger.Log("Invalid item namedID: " + a, "ERROR"), !1)
        },
        onProjectileHit: function(a, b, c) {
            (this.__func = this.throwableFunctions[b.id]) && this.__func(a, b, c)
        },
        TYPE_BASE: "createItem",
        TYPE_FOOD: "createFoodItem",
        TYPE_ARMOR: "createArmorItem",
        TYPE_THROWABLE: "createThrowableItem",
        setPrototype: function(a,
            b) {
            var c = IdentifierRegistry.genItemID(a),
                d;
            for (d in ITEM_BASE_PROTOTYPE) b[d] || (b[d] = ITEM_BASE_PROTOTYPE[d]);
            b.id = c;
            b.stringID = a;
            b.__define(null);
            b.__describe(null);
            b.init()
        }
    };
Callback.addCallback("ProjectileHit", function(a, b, c) {
    if (b) ItemRegistry.onProjectileHit(a, b, c)
});
var ArmorRegistry = {
    armorFuncs: {},
    registerFuncsForID: function(a, b) {
        this.armorFuncs[a] = b
    },
    registerFuncs: function(a, b) {
        var c = ItemRegistry.idSource[a];
        if (!c) return Logger.Log("Invalid item namedID: " + a, "ERROR"), !1;
        this.registerFuncsForID(c, b)
    },
    getForSlot: function(a) {
        return this.armorFuncs[a.id] || {}
    },
    tickCallback: function() {
        for (var a = PlayerAPI.getInventory("armor", !0, !0), b = !1, c = 0; 4 > c; c++) {
            var d = a.getSlot("arm" + c),
                e = this.getForSlot(d);
            e.tick && e.tick(d, a, c) && (b = !0)
        }
        b && a.applyArm()
    },
    hurtCallback: function(a,
        b) {
        for (var c = PlayerAPI.getInventory("armor", !0, !0), d = !1, e = 0; 4 > e; e++) {
            var f = c.getSlot("arm" + e),
                g = this.getForSlot(f);
            g.hurt && g.hurt(a, b, f, c, e) && (d = !0)
        }
        d && c.applyArm()
    }
};
Callback.addCallback("tick", function() {
    ArmorRegistry.tickCallback()
});
Callback.addCallback("EntityHurt", function(a, b, c) {
    b == getPlayerEnt() && ArmorRegistry.hurtCallback(a, c)
});
var ToolAPI = {
    blockMaterials: {},
    toolMaterials: {},
    toolData: {},
    blockData: {},
    needDamagableItemFix: 17 == MCPE_VERSION.main,
    addBlockMaterial: function(a, b) {
        this.blockMaterials[a] = {
            multiplier: b,
            name: a
        }
    },
    addToolMaterial: function(a, b) {
        b.efficiency || (b.efficiency = 1);
        b.damage || (b.damage = 0);
        b.durability || (b.durability = 1);
        b.level || (b.level = 0);
        b.name = a;
        this.toolMaterials[a] = b
    },
    registerTool: function(a, b, c, d) {
        d || (d = {});
        d.brokenId || (d.brokenId = 0);
        d.damage || (d.damage = 0);
        d.toolMaterial = "object" == typeof b ? b : this.toolMaterials[b];
        if (d.toolMaterial) {
            d.blockMaterials = {};
            for (var e in c) d.blockMaterials[c[e]] = !0;
            d.calcDestroyTime || (d.calcDestroyTime = function(a, b, c, d) {
                return d
            });
            this.toolData[a] = d;
            Item.setMaxDamage(a, d.toolMaterial.durability)
        } else Logger.Log("Item " + a + " cannot be registred as tool: tool material " + b + " not found", "ERROR")
    },
    registerSword: function(a, b, c) {
        c = c || {};
        c.isWeapon = !0;
        this.registerTool(a, b, ["fibre"], c)
    },
    registerBlockMaterial: function(a, b, c) {
        var d = this.blockMaterials[b];
        d ? this.blockData[a] = {
            material: d,
            level: c ||
                0
        } : Logger.Log("Material for block " + a + " cannot be registred: material " + b + " not found", "ERROR")
    },
    registerBlockDiggingLevel: function(a, b) {
        this.blockData[a] ? this.blockData[a].level = b : Logger.Log("Digging level for block " + a + " cannot be registred: block has no material", "ERROR")
    },
    registerBlockMaterialAsArray: function(a, b) {
        for (var c in b) this.registerBlockMaterial(b[c], a)
    },
    destroyTimeData: [],
    refresh: function() {
        for (var a = 0; 256 > a; a++) this.destroyTimeData[a] = Block.getDestroyTime(a)
    },
    getBlockData: function(a) {
        return this.blockData[a]
    },
    getBlockMaterial: function(a) {
        return (a = this.getBlockData(a)) ? a.material : null
    },
    getBlockDestroyLevel: function(a) {
        return (a = this.getBlockData(a)) ? a.level : 0
    },
    getEnchantExtraData: function(a) {
        var b = {},
            c;
        for (c in a) {
            var d = a[c];
            b[d.type] = d.level
        }
        a = {
            map: b,
            efficiency: 0,
            unbreaking: 0,
            fortune: 0,
            experience: 0,
            silk: !1
        };
        b[Enchantment.EFFICIENCY] && (a.efficiency = b[Enchantment.EFFICIENCY]);
        b[Enchantment.UNBREAKING] && (a.unbreaking = b[Enchantment.UNBREAKING]);
        b[Enchantment.FORTUNE] && (a.fortune = b[Enchantment.FORTUNE]);
        b[Enchantment.SILK_TOUCH] &&
            (a.silk = !0);
        return a
    },
    fortuneDropModifier: function(a, b) {
        for (var c = a.length, d = 0; d < c; d++) {
            var e;
            a: {
                for (e = b; 0 < e; e--)
                    if (Math.random() < 1 / (2 + b)) {
                        e += 1;
                        break a
                    }
                e = 1
            }--e;
            for (var f = 0; f < e; f++) a.push(a[d])
        }
        return a
    },
    getDestroyTimeViaTool: function(a, b, c, d) {
        var e = UnlimitedAPI.GetReal(a.id, a.data).id,
            e = this.destroyTimeData[e],
            f = this.toolData[b.id],
            g = this.getBlockData(a.id);
        if (!g || !f) return e;
        var h = g.material,
            g = g.level;
        if (!h || f.isNative && !d) return e;
        d = f.blockMaterials[h.name] && f.toolMaterial.level >= g;
        g = this.getEnchantExtraData(b.enchant);
        f.modifyEnchant && f.modifyEnchant(g, b, c, a);
        var k = c = 1;
        d && (c = f.toolMaterial.efficiency * h.multiplier, k = Math.pow(1.3, Math.pow(2, g.efficiency) - 1));
        return f.calcDestroyTime(b, a, {
            base: e,
            devider: c,
            modifier: k
        }, e / c / k, g)
    },
    getToolData: function(a) {
        return this.toolData[a] || null
    },
    getToolLevel: function(a) {
        return (a = this.getToolData(a)) ? a.toolMaterial.level : 0
    },
    getToolLevelViaBlock: function(a, b) {
        var c = this.getToolData(a),
            d = this.getBlockMaterial(b);
        return c && d ? c.blockMaterials[d.name] ? c.toolMaterial.level : 0 : 0
    },
    getCarriedToolData: function() {
        return this.getToolData(UnlimitedAPIAccess.getCarriedItem().id)
    },
    getCarriedToolLevel: function() {
        return this.getToolLevel(UnlimitedAPIAccess.getCarriedItem().id)
    },
    startDestroyHook: function(a, b, c) {
        a = this.getDestroyTimeViaTool(b, UnlimitedAPIAccess.getCarriedItem(!0), a);
        b = UnlimitedAPI.GetReal(b.id, b.data);
        73 == b.id && Block.setDestroyTime(74, a);
        74 == b.id && Block.setDestroyTime(73, a);
        Block.setDestroyTime(b.id, a)
    },
    destroyBlockHook: function(a, b, c) {
        var d = this.getCarriedToolData(),
            e = this.getEnchantExtraData(c.enchant);
        if (d && !d.isNative) {
            d.modifyEnchant && d.modifyEnchant(e, c,
                a, b);
            Math.random() < 1 / (e.unbreaking + 1) && (c.data++, d.isWeapon && c.data++);
            if (d.onDestroy) d.onDestroy(c, a, b);
            c.data >= d.toolMaterial.durability && (e = !0, d.onBroke && d.onBroke(c, a, b) && (e = !1), e && (c.id = d.brokenId, c.count = 1, c.data = 0, WorldAPI.playSoundAtEntity(getPlayerEnt(), "random.break", 100)));
            PlayerAPI.setCarriedItem(c.id, c.count, c.data, c.enchant, c.name)
        }
    },
    LastAttackTime: 0,
    playerAttackHook: function(a, b, c) {
        var d = this.getCarriedToolData(),
            e = this.getEnchantExtraData(c.enchant);
        a = WorldAPI.getThreadTime();
        var f =
            this.LastAttackTime + 10 < a;
        this.needDamagableItemFix && f && 0 < Item.getMaxDamage(c.id) && 512 < c.id && (c.data -= 2, PlayerAPI.setCarriedItem(c.id, c.count, c.data, c.enchant, c.name), this.LastAttackTime = a);
        if (d && !d.isNative && f && 0 < Entity.getHealth(b)) {
            d.modifyEnchant && d.modifyEnchant(e, c, coords, block);
            Math.random() < 1 / (e.unbreaking + 1) && (c.data++, d.isWeapon || c.data++);
            if (d.onAttack) d.onAttack(c, b);
            c.data >= d.durability && (e = !0, d.onBroke && d.onBroke(c) && (e = !1), e && (c.id = d.brokenId, c.count = 1, c.data = 0));
            e = Entity.getHealth(b);
            d = d.damage + d.toolMaterial.damage;
            d = Math.floor(d) + (Math.random() < d - Math.floor(d) ? 1 : 0);
            Entity.setHealth(b, e - (Math.min(d, e) - 1));
            PlayerAPI.setCarriedItem(c.id, c.count, c.data, c.enchant, c.name);
            this.LastAttackTime = a
        }
    },
    resetEngine: function() {
        this.LastAttackTime = 0;
        this.refresh()
    },
    dropExpOrb: function(a, b, c, d) {
        var e = Level.spawnMob(a, b, c, EntityType.EXPERIENCE_ORB);
        EntityAPI.putExtraJson(e, "__exp", {
            value: d,
            baseCoords: {
                x: a,
                y: b,
                z: c
            }
        })
    },
    dropExpOrbs: function(a, b, c, d) {
        for (; 2 < d;) {
            var e = parseInt(d / 2);
            this.dropExpOrb(a,
                b, c, e);
            d -= e
        }
        0 < d && this.dropExpOrb(a, b, c, d)
    },
    dropOreExp: function(a, b, c, d) {
        this.dropExpOrbs(a.x + .5, a.y + .5, a.z + .5, b + parseInt(Math.random() * (c - b + 1 + d)))
    },
    checkOrbRemoved: function(a, b) {
        if (b == EntityType.EXPERIENCE_ORB) {
            var c = EntityAPI.getExtraJson(a, "__exp");
            c && c.value && (PlayerAPI.addExperience(c.value), Callback.invokeCallback("CustomExpOrbReceived", a, c))
        }
    }
};
Callback.addCallback("DestroyBlock", function(a, b) {
    var c = UnlimitedAPIAccess.getCarriedItem(!0, !0);
    ToolAPI.destroyBlockHook(a, b, c)
});
Callback.addCallback("DestroyBlockStart", function(a, b) {
    var c = UnlimitedAPIAccess.getCarriedItem(!0, !0);
    ToolAPI.startDestroyHook(a, b, c)
});
Callback.addCallback("PlayerAttack", function(a, b) {
    var c = UnlimitedAPIAccess.getCarriedItem(!0, !0);
    ToolAPI.playerAttackHook(a, b, c)
});
Callback.addCallback("EntityRemoved", function(a, b) {
    ToolAPI.checkOrbRemoved(a, b)
});
Callback.addCallback("PostLoaded", function() {
    ToolAPI.resetEngine()
});
ToolAPI.addToolMaterial("wood", {
    level: 1,
    durability: 60,
    damage: 2,
    efficiency: 2
});
ToolAPI.addToolMaterial("stone", {
    level: 2,
    durability: 132,
    damage: 3,
    efficiency: 4
});
ToolAPI.addToolMaterial("iron", {
    level: 3,
    durability: 251,
    damage: 4,
    efficiency: 6
});
ToolAPI.addToolMaterial("golden", {
    level: 1,
    durability: 33,
    damage: 2,
    efficiency: 12
});
ToolAPI.addToolMaterial("diamond", {
    level: 4,
    durability: 1562,
    damage: 5,
    efficiency: 12
});
ToolAPI.addBlockMaterial("stone", 5);
ToolAPI.addBlockMaterial("wood", 1.5);
ToolAPI.addBlockMaterial("dirt", 1.5);
ToolAPI.addBlockMaterial("plant", 1.5);
ToolAPI.addBlockMaterial("fibre", 1.5);
ToolAPI.addBlockMaterial("cobweb", 5);
ToolAPI.addBlockMaterial("unbreaking", 999999999);
ToolAPI.registerTool(270, "wood", ["stone"], {
    isNative: !0,
    damage: 1
});
ToolAPI.registerTool(274, "stone", ["stone"], {
    isNative: !0,
    damage: 1
});
ToolAPI.registerTool(257, "iron", ["stone"], {
    isNative: !0,
    damage: 1
});
ToolAPI.registerTool(285, "golden", ["stone"], {
    isNative: !0,
    damage: 1
});
ToolAPI.registerTool(278, "diamond", ["stone"], {
    isNative: !0,
    damage: 1
});
ToolAPI.registerTool(271, "wood", ["wood"], {
    isNative: !0,
    damage: 2
});
ToolAPI.registerTool(275, "stone", ["wood"], {
    isNative: !0,
    damage: 2
});
ToolAPI.registerTool(258, "iron", ["wood"], {
    isNative: !0,
    damage: 2
});
ToolAPI.registerTool(286, "golden", ["wood"], {
    isNative: !0,
    damage: 2
});
ToolAPI.registerTool(279, "diamond", ["wood"], {
    isNative: !0,
    damage: 2
});
ToolAPI.registerTool(269, "wood", ["dirt"], {
    isNative: !0,
    damage: 0
});
ToolAPI.registerTool(273, "stone", ["dirt"], {
    isNative: !0,
    damage: 0
});
ToolAPI.registerTool(256, "iron", ["dirt"], {
    isNative: !0,
    damage: 0
});
ToolAPI.registerTool(284, "golden", ["dirt"], {
    isNative: !0,
    damage: 0
});
ToolAPI.registerTool(277, "diamond", ["dirt"], {
    isNative: !0,
    damage: 0
});
ToolAPI.registerBlockMaterialAsArray("stone", [1, 4, 14, 15, 16, 21, 22, 23, 24, 27, 28, 29, 33, 41, 42, 43, 44, 45, 48, 49, 52, 56, 57, 61, 62, 66, 67, 69, 70, 71, 73, 74, 77, 87, 89, 93, 94, 97, 98, 101, 108, 109, 112, 113, 114, 116, 117, 118, 120, 121, 123, 124, 125, 126, 128, 129, 133, 139, 140, 145, 147, 148, 149, 150, 151, 178, 152, 153, 154, 155, 156, 167, 172, 173, 179, 180, 181, 182, 245, 251, 79, 174]);
ToolAPI.registerBlockMaterialAsArray("wood", [5, 17, 25, 47, 53, 54, 58, 63, 68, 64, 65, 72, 85, 96, 107, 131, 134, 135, 136, 163, 164, 143, 146, 157, 158, 162, 183, 184, 185, 186, 187, 193, 194, 195, 196, 197]);
ToolAPI.registerBlockMaterialAsArray("dirt", [2, 3, 12, 13, 60, 78, 80, 88, 110, 144, 159, 198, 243]);
ToolAPI.registerBlockMaterialAsArray("fibre", [19, 26, 30, 46, 50, 51, 55, 75, 76, 86, 91, 99, 100, 103, 132, 170, 199]);
ToolAPI.registerBlockMaterialAsArray("plant", [6, 18, 161, 31, 32, 37, 38, 39, 40, 175, 59, 141, 142, 244, 81, 83, 104, 105, 106, 111, 115, 127]);
ToolAPI.registerBlockMaterialAsArray("cobweb", []);
ToolAPI.registerBlockMaterialAsArray("unbreaking", [8, 9, 10, 11, 7, 95]);
BlockRegistry.registerDropFunctionForID(1, function(a, b, c, d, e) {
    return 0 < d ? 0 != c || e.silk ? [
        [b, 1, c]
    ] : [
        [4, 1, 0]
    ] : []
}, 1);
BlockRegistry.setDestroyLevelForID(4, 1);
BlockRegistry.setDestroyLevelForID(14, 3);
BlockRegistry.setDestroyLevelForID(15, 2);
BlockRegistry.registerDropFunctionForID(16, function(a, b, c, d, e) {
    if (1 <= d) {
        if (e.silk) return [
            [b, 1, c]
        ];
        ToolAPI.dropOreExp(a, 0, 2, e.experience);
        return ToolAPI.fortuneDropModifier([
            [263, 1, 0]
        ], e.fortune)
    }
    return []
}, 1);
BlockRegistry.registerDropFunctionForID(21, function(a, b, c, d, e) {
    if (1 <= d) {
        if (e.silk) return [
            [b, 1, c]
        ];
        b = [];
        c = 4 + parseInt(2 * Math.random());
        for (d = 0; d < c; d++) b.push([351, 1, 4]);
        ToolAPI.dropOreExp(a, 2, 5, e.experience);
        return ToolAPI.fortuneDropModifier(b, e.fortune)
    }
    return []
}, 2);
BlockRegistry.registerDropFunctionForID(30, function(a, b, c, d, e) {
    return 1 <= d ? [
        [287, 1, 0]
    ] : []
}, 1);
BlockRegistry.setDestroyLevelForID(22, 2);
BlockRegistry.setDestroyLevelForID(41, 3);
BlockRegistry.setDestroyLevelForID(42, 3);
BlockRegistry.registerDropFunctionForID(43, function(a, b, c, d, e) {
    return 1 <= d ? [
        [44, 1, c],
        [44, 1, c]
    ] : []
}, 1);
BlockRegistry.setDestroyLevelForID(44, 1);
BlockRegistry.setDestroyLevelForID(45, 1);
BlockRegistry.setDestroyLevelForID(48, 1);
BlockRegistry.setDestroyLevelForID(49, 4);
BlockRegistry.registerDropFunctionForID(52, function(a, b, c, d, e) {
    ToolAPI.dropOreExp(a, 15, 43, e.experience);
    return []
}, 1);
BlockRegistry.registerDropFunctionForID(56, function(a, b, c, d, e) {
    if (3 <= d) {
        if (e.silk) return [
            [b, 1, c]
        ];
        ToolAPI.dropOreExp(a, 3, 7, e.experience);
        return ToolAPI.fortuneDropModifier([
            [264, 1, 0]
        ], e.fortune)
    }
    return []
}, 3);
BlockRegistry.setDestroyLevelForID(57, 3);
BlockRegistry.setDestroyLevelForID(61, 1);
BlockRegistry.registerDropFunctionForID(62, function(a, b, c, d, e) {
    return 1 <= d ? [
        [61, 1, 0]
    ] : []
}, 1);
BlockRegistry.setDestroyLevelForID(67, 1);
BlockRegistry.setDestroyLevelForID(70, 1);
BlockRegistry.registerDropFunctionForID(71, function(a, b, c, d, e) {
    return 2 <= d ? [
        [330, 1, 0]
    ] : []
}, 2);
BlockRegistry.registerDropFunctionForID(73, function(a, b, c, d, e) {
    if (3 <= d) {
        if (e.silk) return [
            [b, 1, c]
        ];
        ToolAPI.dropOreExp(a, 2, 5, e.experience);
        a = [];
        b = 4 + parseInt(2 * Math.random());
        for (c = 0; c < b; c++) a.push([331, 1, 0]);
        return ToolAPI.fortuneDropModifier(a, e.fortune)
    }
    return []
}, 3);
BlockRegistry.registerDropFunctionForID(74, function(a, b, c, d, e) {
    if (3 <= d) {
        if (e.silk) return [
            [b, 1, c]
        ];
        ToolAPI.dropOreExp(a, 2, 5, e.experience);
        a = [];
        b = 4 + parseInt(2 * Math.random());
        for (c = 0; c < b; c++) a.push([331, 1, 0]);
        return ToolAPI.fortuneDropModifier(a, e.fortune)
    }
    return []
}, 3);
BlockRegistry.setDestroyLevelForID(77, 1);
BlockRegistry.setDestroyLevelForID(87, 1);
BlockRegistry.setDestroyLevelForID(98, 1);
BlockRegistry.setDestroyLevelForID(101, 2);
BlockRegistry.setDestroyLevelForID(108, 1);
BlockRegistry.setDestroyLevelForID(109, 1);
BlockRegistry.setDestroyLevelForID(112, 2);
BlockRegistry.setDestroyLevelForID(113, 2);
BlockRegistry.setDestroyLevelForID(114, 2);
BlockRegistry.setDestroyLevelForID(116, 2);
BlockRegistry.setDestroyLevelForID(117, 1);
BlockRegistry.setDestroyLevelForID(118, 1);
BlockRegistry.setDestroyLevelForID(121, 2);
BlockRegistry.setDestroyLevelForID(125, 1);
BlockRegistry.setDestroyLevelForID(128, 1);
BlockRegistry.registerDropFunctionForID(129, function(a, b, c, d, e) {
    if (3 <= d) {
        if (e.silk) return [
            [b, 1, c]
        ];
        ToolAPI.dropOreExp(a, 3, 7, e.experience);
        return ToolAPI.fortuneDropModifier([
            [388, 1, 0]
        ], e.fortune)
    }
    return []
}, 3);
BlockRegistry.setDestroyLevelForID(133, 3);
BlockRegistry.setDestroyLevelForID(139, 1);
BlockRegistry.setDestroyLevelForID(135, 2);
BlockRegistry.setDestroyLevelForID(147, 2);
BlockRegistry.setDestroyLevelForID(148, 2);
BlockRegistry.setDestroyLevelForID(152, 3);
BlockRegistry.registerDropFunctionForID(153, function(a, b, c, d, e) {
    if (2 <= d) {
        if (e.silk) return [
            [b, 1, c]
        ];
        ToolAPI.dropOreExp(a, 2, 5, e.experience);
        a = [];
        b = 1 + parseInt(3 * Math.random());
        for (c = 0; c < b; c++) a.push([406, 1, 0]);
        return ToolAPI.fortuneDropModifier(a, e.fortune)
    }
    return []
}, 2);
BlockRegistry.setDestroyLevelForID(154, 1);
BlockRegistry.setDestroyLevelForID(155, 2);
BlockRegistry.setDestroyLevelForID(156, 2);
BlockRegistry.setDestroyLevelForID(167, 2);
BlockRegistry.setDestroyLevelForID(172, 1);
BlockRegistry.setDestroyLevelForID(173, 1);
BlockRegistry.setDestroyLevelForID(179, 1);
BlockRegistry.setDestroyLevelForID(180, 1);
BlockRegistry.registerDropFunctionForID(181, function(a, b, c, d, e) {
    return 1 <= d ? [
        [182, 1, c],
        [182, 1, c]
    ] : []
}, 1);
BlockRegistry.setDestroyLevelForID(182, 1);
BlockRegistry.setDestroyLevelForID(245, 1);
BlockRegistry.setDestroyLevelForID(251, 1);
var RecipeRegistry = {
    addShaped: function(a, b, c, d, e) {
        try {
            NativeWorkbench.addShapedRecipe(a, b, c, d, e)
        } catch (f) {
            Logger.Log("failed to add workbench shaped recipe for [" + [a.id, a.count, a.data] + "]: " + f, "ERROR")
        }
    },
    addShapedNative: function(a, b, c, d, e, f, g) {
        this.addShaped({
            id: a,
            count: b,
            data: c
        }, d, e, f, g)
    },
    addShapeless: function(a, b, c, d) {
        try {
            NativeWorkbench.addShapelessRecipe(a, b, c, d)
        } catch (e) {
            Logger.Log("failed to add workbench shapeless recipe for [" + [a.id, a.count, a.data] + "]: " + e, "ERROR")
        }
    },
    deleteRecipe: function(a) {
        try {
            NativeWorkbench.clearItemRecipes(a)
        } catch (b) {
            Logger.Log("failed to delete workbench shapeless recipe for [" + [a.id, a.count, a.data] + "]: " + b, "ERROR")
        }
    },
    replaceWithShaped: function(a, b, c, d, e) {
        this.deleteRecipe(a);
        this.addShaped(a, b, c, d, e)
    },
    replaceWithShapeless: function(a, b, c, d) {
        this.deleteRecipe(a);
        this.addShapeless(a, b, c, d)
    },
    getFieldContainer: function(a) {
        if (a.getSlot) return a;
        for (var b = new Container, c = 0; 9 > c; c++) {
            var d = a[c];
            d ? b.slots["slot" + c] = d : b.setSlot("slot" + c, 0, 0, 0)
        }
        return b
    },
    getRecipeByField: function(a, b, c) {
        a = this.getFieldContainer(a);
        a = NativeWorkbench.getFieldData(a);
        return (a = NativeWorkbench.getRecipeByField(a)) &&
            (NativeWorkbench.checkRecipePrefix(a, b) || c) ? a : null
    },
    getRecipeResult: function(a, b) {
        var c = this.getFieldContainer(a),
            c = NativeWorkbench.getFieldData(c);
        return (c = NativeWorkbench.getRecipeByField(c)) && NativeWorkbench.checkRecipePrefix(c, b) ? {
            id: c.recipeResult.id,
            count: c.recipeResult.count,
            data: c.recipeResult.data
        } : null
    },
    provideRecipe: function(a, b) {
        var c = this.getFieldContainer(a),
            d = NativeWorkbench.container,
            e = this.getRecipeResult(c, b);
        return e && (NativeWorkbench.container = c, c = NativeWorkbench.onItemCrafed(e,
            c, b), NativeWorkbench.container = d, c) ? e : null
    },
    getWorkbenchUI: function() {
        return coreEngineConfig.access("util.pocket_workbench_style") ? coreEngineConfig.access("util.split_pocket_workbench_to_pages") ? PEWorkbenchUIScreen_splitted : PEWorkbenchUIScreen : PCWorkbenchUIScreen
    },
    getRecipesByResult: function(a, b, c) {
        var d = [],
            e;
        for (e in NativeWorkbench.recipes) {
            var f = NativeWorkbench.recipes[e],
                g;
            for (g in f) {
                var h = f[g];
                if (!h.offset || !h.offset.x && !h.offset.y) {
                    var k = h.recipeResult;
                    k.id != a || !(k.count >= b || -1 == b) || k.data !=
                        c && -1 != c || d.push(h)
                }
            }
        }
        return d
    },
    furnaceRecipes: {
        4: {
            resultId: 1,
            resultData: 0,
            isNative: !0
        },
        12: {
            resultId: 20,
            resultData: 0,
            isNative: !0
        },
        14: {
            resultId: 266,
            resultData: 0,
            isNative: !0
        },
        15: {
            resultId: 265,
            resultData: 0,
            isNative: !0
        },
        17: {
            resultId: 263,
            resultData: 0,
            isNative: !0
        },
        87: {
            resultId: 405,
            resultData: 0,
            isNative: !0
        },
        263: {
            resultId: 263,
            resultData: 1,
            isNative: !0
        },
        319: {
            resultId: 320,
            resultData: 0,
            isNative: !0
        },
        337: {
            resultId: 336,
            resultData: 0,
            isNative: !0
        },
        349: {
            resultId: 350,
            resultData: 0,
            isNative: !0
        },
        363: {
            resultId: 364,
            resultData: 0,
            isNative: !0
        },
        365: {
            resultId: 366,
            resultData: 0,
            isNative: !0
        },
        392: {
            resultId: 393,
            resultData: 0,
            isNative: !0
        },
        460: {
            resultId: 463,
            resultData: 0,
            isNative: !0
        }
    },
    isFurnaceAdded: !1,
    addFurnace: function(a, b, c, d, e) {
        4096 < a ? Logger.Log("furnace recipes do not support blocks, defined with unlimited api as recipe source", "ERROR") : (this.furnaceRecipes[a] = {
            resultId: b,
            resultData: c,
            prefix: d,
            isLocked: e
        }, this.isFurnaceAdded && !d && this.addFurnaceNative(a, b, c))
    },
    addFurnaceNative: function(a, b, c) {
        var d = UnlimitedAPI.GetReal(b, c);
        try {
            Item.addFurnaceRecipe(a,
                d.id, d.data)
        } catch (e) {
            Logger.Log("cannot add furnace recipe [" + a + " -> " + b + "," + c + "]: " + e, "ERROR")
        }
    },
    addAllFurnaceRecipes: function() {
        if (!this.isFurnaceAdded) {
            for (var a in this.furnaceRecipes) {
                var b = this.furnaceRecipes[a];
                !b || b.isNative || b.prefix || this.addFurnaceNative(parseInt(a), b.resultId, b.resultData)
            }
            this.isFurnaceAdded = !0
        }
    },
    doesFurnacePrefixesMatch: function(a, b) {
        return a && -1 == (b || "").indexOf(a) ? !1 : !0
    },
    getFurnaceRecipeResult: function(a, b) {
        var c = this.furnaceRecipes[a];
        return c && this.doesFurnacePrefixesMatch(c.prefix,
            b) ? {
            id: c.resultId,
            data: c.resultData
        } : null
    },
    removeFurnaceRecipe: function(a) {
        var b = this.furnaceRecipes[a];
        if (b.isNative || b.isLocked) return Logger.Log("cannot remove furnace recipe " + a + ": it is native or locked", "ERROR"), !1;
        if (!b.prefix && this.isFurnaceAdded) return Logger.Log("cannot remove furnace recipe " + a + ": all recipes with no prefix loaded at level-loading", "ERROR"), !1;
        delete this.furnaceRecipes[a];
        return !0
    }
};
Callback.addCallback("LevelLoaded", function() {
    RecipeRegistry.addAllFurnaceRecipes()
});
var LiquidRegistry = {
    liquids: {},
    registerLiquid: function(a, b, c, d) {
        this.liquids[a] && Logger.Log("liquid key " + a + " is not unique, new liquid will replace old one", "WARNING");
        this.liquids[a] = {
            key: a,
            name: b || a,
            uiTextures: c || [],
            uiCache: {},
            modelTextures: d || []
        }
    },
    getLiquidData: function(a) {
        return this.liquids[a]
    },
    isExists: function(a) {
        return this.liquids[a] ? !0 : !1
    },
    getLiquidName: function(a) {
        if (this.liquids[a]) return this.liquids[a].name
    },
    getLiquidUITexture: function(a, b, c) {
        if (a = this.getLiquidData(a)) return a.uiTextures[0]
    },
    getLiquidUIBitmap: function(a, b, c) {
        var d = this.getLiquidData(a);
        if (d) {
            var e = parseInt(b / 2) + ":" + parseInt(c / 2),
                f = b / c,
                g = null,
                h = 99999,
                k;
            for (k in d.uiTextures)
                if (a = GuiAPI.getBitmapFromCache(d.uiTextures[k])) {
                    var m = Math.abs(a.width / a.height - f);
                    m < h && (h = m, g = a)
                }
            if (g && 1 <= b && 1 <= c) return a = android.graphics.Bitmap.createScaledBitmap(g, b, c, !1), d.uiCache[e] = a
        }
    },
    FullByEmpty: {},
    EmptyByFull: {},
    registerItem: function(a, b, c) {
        this.getLiquidData(a) && b && c ? (this.FullByEmpty[b.id + ":" + b.data + ":" + a] = {
            id: c.id,
            data: c.data
        }, this.EmptyByFull[c.id +
            ":" + c.data] = {
            id: b.id,
            data: b.data,
            liquid: a
        }) : Logger.Log("cannot register items for liquid " + key + ": some params are missing or invalid", "ERROR")
    },
    getEmptyItem: function(a, b) {
        if (this.EmptyByFull[a + ":" + b]) return this.EmptyByFull[a + ":" + b];
        if (this.EmptyByFull[a + ":-1"]) return this.EmptyByFull[a + ":-1"]
    },
    getItemLiquid: function(a, b) {
        var c = this.getEmptyItem(a, b);
        if (c) return c.liquid
    },
    getFullItem: function(a, b, c) {
        if (this.FullByEmpty[a + ":" + b + ":" + c]) return this.FullByEmpty[a + ":" + b + ":" + c];
        if (this.FullByEmpty[a + ":-1:" +
                c]) return this.FullByEmpty[a + ":-1:" + c]
    },
    Storage: function(a) {
        this.liquidAmounts = {};
        this.liquidLimits = {};
        this.tileEntity = a;
        this.hasDataFor = function(a) {
            return "undefined" != this.liquidAmounts[a] + ""
        };
        this.setLimit = function(a, c) {
            a ? this.liquidLimits[a] = c : this.liquidLimits.__global = c
        };
        this.getLimit = function(a) {
            return this.liquidLimits[a] || this.liquidLimits.__global || 99999999
        };
        this.getAmount = function(a) {
            return this.liquidAmounts[a] || 0
        };
        this.getRelativeAmount = function(a) {
            return this.getAmount(a) / this.getLimit(a)
        };
        this.updateUiScale = function(a, c, d) {
            d ? d.setScaleAsLiquid(a, c, this.getRelativeAmount(c)) : this.tileEntity && this.tileEntity.container.setScaleAsLiquid(a, c, this.getRelativeAmount(c))
        };
        this.setAmount = function(a, c) {
            this.liquidAmounts[a] = c
        };
        this.getLiquidStored = function() {
            for (var a in this.liquidAmounts)
                if (0 < this.liquidAmounts[a]) return a;
            return null
        };
        this.isFull = function(a) {
            if (a) return this.getLimit(a) <= this.liquidAmounts[a];
            for (var b in this.liquidAmounts)
                if (b && !this.isFull(b)) return !1;
            return !0
        };
        this.isEmpty =
            function(a) {
                if (a) return 0 >= this.liquidAmounts[a];
                for (var b in this.liquidAmounts)
                    if (b && !this.isEmpty(b)) return !1;
                return !0
            };
        this.addLiquid = function(a, c, d) {
            var b = this.getLimit(a),
                f = this.getAmount(a) + c,
                b = f - Math.min(b, f);
            return !d || 0 >= b ? (this.setAmount(a, f - b), Math.max(b, 0)) : c
        };
        this.getLiquid_flag = !1;
        this.getLiquid = function(a, c, d) {
            var b = this.getAmount(a);
            !this.getLiquid_flag && this.tileEntity && b < c && (this.getLiquid_flag = !0, this.tileEntity.requireMoreLiquid(a, c - b), this.getLiquid_flag = !1, b = this.getAmount(a));
            var f = Math.min(b, c);
            return !d || f >= c ? (this.setAmount(a, b - f), f) : 0
        };
        this.save = function() {
            return {
                amounts: this.liquidAmounts,
                limits: this.liquidLimits
            }
        };
        this.read = function(a) {
            a && (a.amounts && (this.liquidAmounts = a.amounts), a.limits && (this.liquidLimits = a.limits))
        }
    }
};
LiquidRegistry.registerLiquid("water", "water", ["standart_water_ui_texture"]);
LiquidRegistry.registerLiquid("lava", "lava", ["standart_lava_ui_texture"]);
LiquidRegistry.registerLiquid("milk", "milk", ["standart_milk_ui_texture"]);
LiquidRegistry.registerItem("water", {
    id: 325,
    data: 0
}, {
    id: 325,
    data: 8
});
LiquidRegistry.registerItem("water", {
    id: 374,
    data: 0
}, {
    id: 373,
    data: 0
});
LiquidRegistry.registerItem("lava", {
    id: 325,
    data: 0
}, {
    id: 325,
    data: 10
});
LiquidRegistry.registerItem("milk", {
    id: 325,
    data: 0
}, {
    id: 325,
    data: 1
});

function ChestContainer(a, b, c) {
    this.parent = Container;
    this.parent();
    this.SLOT_COUNT = 27;
    this.slots = {};
    this._type = "chest";
    this.coords = {
        x: a,
        y: b,
        z: c
    };
    this.setSlotCount = function(a) {
        this.SLOT_COUNT = a || 0
    };
    this.refreshSlots = function() {
        for (var a = 0; a < this.SLOT_COUNT; a++) this.slots[a] = {
            id: Level.getChestSlot(this.coords.x, this.coords.y, this.coords.z, a),
            count: Level.getChestSlotCount(this.coords.x, this.coords.y, this.coords.z, a),
            data: Level.getChestSlotData(this.coords.x, this.coords.y, this.coords.z, a)
        }
    };
    this.applyChanges =
        function() {
            for (var d in this.slots) {
                var e = this.slots[d];
                e && Level.setChestSlot(a, b, c, d, e.id, e.data, e.count)
            }
        }
}

function FurnaceContainer(a, b, c) {
    this.parent = Container;
    this.parent();
    this.SLOT_COUNT = 3;
    this.slots = {};
    this._type = "furnace";
    this.coords = {
        x: a,
        y: b,
        z: c
    };
    this.setSlotCount = function(a) {
        this.SLOT_COUNT = a || 0
    };
    this.refreshSlots = function() {
        for (var a = 0; a < this.SLOT_COUNT; a++) this.slots[a] = {
            id: Level.getFurnaceSlot(this.coords.x, this.coords.y, this.coords.z, a),
            count: Level.getFurnaceSlotCount(this.coords.x, this.coords.y, this.coords.z, a),
            data: Level.getFurnaceSlotData(this.coords.x, this.coords.y, this.coords.z, a)
        }
    };
    this.applyChanges = function() {
        for (var d in this.slots) {
            var e = this.slots[d];
            e && Level.setFurnaceSlot(a, b, c, d, e.id, e.data, e.count)
        }
    }
}
var WorldAPI = {
    isLoaded: !1,
    setLoaded: function(a) {
        (this.isLoaded = a) ? (a = this.__inworld, Logger.Log("World API switched into in-game mode", "API")) : (a = this.__inmenu, Logger.Log("World API switched into in-menu mode", "API"));
        for (var b in a) this[b] = a[b]
    },
    isWorldLoaded: function() {
        return this.isLoaded
    },
    getThreadTime: function() {
        return TickingThread.getTime()
    },
    __inworld: {
        nativeSetBlock: function(a, b, c, d, e) {
            setTile_origin(a, b, c, d, e)
        },
        nativeGetBlockID: function(a, b, c) {
            return getTile_origin(a, b, c)
        },
        nativeGetBlockData: function(a,
            b, c) {
            return Level.getData_origin(a, b, c)
        },
        setBlock: UnlimitedAPIAccess.setFullTile,
        setFullBlock: function(a, b, c, d) {
            this.setBlock(a, b, c, d.id, d.data)
        },
        getBlock: UnlimitedAPIAccess.getFullTile,
        getBlockID: getTile,
        getBlockData: Level.getData,
        destroyBlock: function(a, b, c, d) {
            var e = this.getBlock(a, b, c);
            if (d) BlockRegistry.onBlockDestroyed({
                x: a,
                y: b,
                z: c
            }, e);
            Level.destroyBlock(a, b, c, d)
        },
        getLightLevel: function(a, b, c) {
            return Level.getBrightness(a, b, c)
        },
        getTileEntity: function(a, b, c) {
            return TileEntity.getTileEntity(a,
                b, c)
        },
        addTileEntity: function(a, b, c) {
            return TileEntity.addTileEntity(a, b, c)
        },
        removeTileEntity: function(a, b, c) {
            return TileEntity.destroyTileEntityAtCoords(a, b, c)
        },
        getContainer: function(a, b, c) {
            var d = this.getBlock(a, b, c);
            return 54 == d.id ? (d = new ChestContainer(a, b, c), d.refreshSlots(), d) : 61 == d.id || 62 == d.id ? (d = new FurnaceContainer(a, b, c), d.refreshSlots(), d) : TileEntity.isTileEntityBlock(d.id) && (a = this.getTileEntity(a, b, c)) && a.container ? (a.container._type = d.id, a.container) : null
        },
        getWorldTime: function() {
            return Level.getTime()
        },
        setWorldTime: function(a) {
            return Level.setTime(a || 0)
        },
        setDayMode: function(a) {
            this.setNightMode(!a)
        },
        setNightMode: function(a) {
            Level.setNightMode(a)
        },
        getWeather: function() {
            return {
                rain: Level.getRainLevel(),
                thunder: Level.getLightningLevel()
            }
        },
        setWeather: function(a) {
            a && (Level.setRainLevel(a.rain || 0), Level.setLightningLevel(a.thunder || 0))
        },
        drop: function(a, b, c, d, e, f) {
            return Level.dropItem(a, b, c, 0, d, e, f)
        },
        explode: function(a, b, c, d, e) {
            explode(a, b, c, d, e)
        },
        getBiome: function(a, b) {
            return Level.getBiome(a, b)
        },
        getBiomeName: function(a,
            b) {
            return Level.getBiomeName(a, b)
        },
        getGrassColor: function(a, b) {
            return Level.getGrassColor(a, b)
        },
        setGrassColor: function(a, b, c) {
            return Level.setGrassColor(a, b, c || 0)
        },
        getGrassColorRGB: function(a, b) {
            var c = Level.getGrassColor(a, b);
            return {
                r: c >> 16 & 255,
                g: c >> 8 & 255,
                b: c >> 0 & 255
            }
        },
        setGrassColorRGB: function(a, b, c) {
            c = 65536 * parseInt(c.r) + 256 * parseInt(c.g) + parseInt(c.b);
            return Level.setGrassColor(a, b, c)
        },
        canSeeSky: function(a, b, c) {
            return Level.canSeeSky(a, b, c)
        },
        playSound: function(a, b, c, d, e, f) {
            f || (f = .5);
            Level.playSound(a,
                b, c, d, e, f)
        },
        playSoundAtEntity: function(a, b, c, d) {
            d || (d = .5);
            Level.playSoundEnt(a, b, c, d)
        }
    },
    __inmenu: {
        nativeSetBlock: function() {},
        nativeGetBlockID: function() {
            return 0
        },
        nativeGetBlockData: function(a, b, c) {
            return 0
        },
        setBlock: function(a, b, c, d, e) {},
        setFullBlock: function(a, b, c, d) {},
        getBlock: function(a, b, c) {
            return {
                id: 0,
                data: 0
            }
        },
        getBlockID: function(a, b, c) {
            return 0
        },
        getBlockData: function(a, b, c) {
            return 0
        },
        destroyBlock: function(a, b, c, d) {},
        getLightLevel: function(a, b, c) {
            return 0
        },
        getTileEntity: function(a, b, c) {
            return null
        },
        addTileEntity: function(a, b, c) {
            return null
        },
        removeTileEntity: function(a, b, c) {
            return !1
        },
        getContainer: function(a, b, c) {
            return null
        },
        getWorldTime: function() {
            return 0
        },
        setWorldTime: function(a) {},
        setDayMode: function(a) {},
        setNightMode: function(a) {},
        getWeather: function() {
            return {
                rain: 0,
                thunder: 0
            }
        },
        setWeather: function(a) {},
        drop: function(a, b, c, d, e, f) {
            return null
        },
        explode: function(a, b, c, d, e) {},
        getBiome: function(a, b) {
            return -1
        },
        getBiomeName: function(a, b) {
            return "error: level not loaded"
        },
        getGrassColor: function(a,
            b) {
            return 0
        },
        setGrassColor: function(a, b, c) {},
        getGrassColorRGB: function(a, b) {
            Level.getGrassColor(a, b);
            return {
                r: 0,
                g: 0,
                b: 0
            }
        },
        setGrassColorRGB: function(a, b, c) {},
        canSeeSky: function(a, b, c) {
            return !1
        },
        playSound: function(a, b, c, d, e, f) {},
        playSoundAtEntity: function(a, b, c, d) {}
    }
};
WorldAPI.setLoaded(!1);
Callback.addCallback("LevelLoaded", function() {
    WorldAPI.setLoaded(!0)
});
Callback.addCallback("LevelLeft", function() {
    WorldAPI.setLoaded(!1)
});
var AnimatorToken = {
    __current: 1,
    genToken: function() {
        return this.__current++
    }
};

function AnimationHelper() {
    this.animation = [];
    this.animationDelay = 1;
    this.animationOffsets = {
        0: 0
    };
    this.getOffset = function(a) {
        return this.animationOffsets[a || 0] || 0
    };
    this.setOffset = function(a, b) {
        this.animationOffsets[a || 0] = b
    };
    this.getGlobalTime = function() {
        return java.lang.System.currentTimeMillis() / 50
    };
    this.getTime = function(a) {
        return this.getGlobalTime() - this.getOffset(a)
    };
    this.resetAnimation = function(a) {
        this.setOffset(a, this.getGlobalTime())
    };
    this.getFrameNumber = function(a) {
        return parseInt(this.getTime(a) /
            this.animationDelay) % this.animation.length
    };
    this.setDelay = function(a) {
        this.animationDelay = a || 1
    };
    this.setAnimation = function(a) {
        this.animation = a
    };
    this.clearAnimation = function() {
        this.animation = []
    };
    this.addFrame = function(a) {
        this.animation.push(a)
    };
    this.getFrame = function(a) {
        return this.animation[this.getFrameNumber(a)]
    };
    this.inherit = function(a) {
        this.clearAnimation();
        this.setDelay(a.animationDelay);
        for (var b in a.animation) this.addFrame(a.animation[b])
    }
}

function Texture(a) {
    this.path = a;
    this.isAnimated = !1;
    this.animator = new AnimationHelper;
    this.resolution = {
        w: 64,
        h: 32
    };
    this.setTexture = function(a) {
        this.path = a;
        this.isAnimated = !1;
        return this
    };
    this.setResolution = function(a, c) {
        this.resolution.w = a;
        this.resolution.h = c || a;
        return this
    };
    this.setAnimation = function(a, c) {
        this.animator.setDelay(c);
        this.animator.setAnimation(a);
        this.isAnimated = !0;
        return this
    };
    this.resetAnimation = function(a) {
        this.animator.resetAnimation(a);
        return this
    };
    this.getTexture = function(a) {
        return this.isAnimated ?
            this.animator.getFrame(a) : this.path
    };
    this.getResolution = function() {
        return {
            w: this.resolution.w * this.pixelScale,
            h: this.resolution.h * this.pixelScale
        }
    };
    this.pixelScale = 1;
    this.setPixelScale = function(a) {
        this.pixelScale = a;
        return this
    }
}
var ce_default_entity_texture = (new Texture("images/mob/ce_default_entity_texture.png")).setPixelScale(8),
    ce_missing_entity_texture = (new Texture("images/mob/ce_missing_entity_texture.png")).setPixelScale(1),
    EntityRenderGlobalCache = {
        globalCache: {},
        saveRenderAPI: function(a, b, c) {
            (c ? a.localCache : this.globalCache)[b] = a.renderObject
        },
        loadRenderAPI: function(a, b, c) {
            c = c ? a.localCache : this.globalCache;
            return c[b] ? (a.renderObject = c[b], a.model = a.renderObject.getModel(), !0) : !1
        }
    };

function RenderAPI(a) {
    a = a || {};
    this.model = this.renderObject = null;
    this.localCache = {};
    this.getID = function() {
        return this.renderObject ? this.renderObject.renderType : -1
    };
    this.toJSON = function() {
        return null
    };
    this.createRaw = function() {
        this.renderObject = Renderer.createHumanoidRenderer();
        this.model = this.renderObject.getModel()
    };
    this.createNative = function(a) {
        this.renderObject = Renderer.get(a);
        this.model = this.renderObject.getModel()
    };
    this.clearModel = function() {
        this.model && (this.model.getPart("head").clear(), this.model.getPart("body").clear(),
            this.model.getPart("rightArm").clear(), this.model.getPart("leftArm").clear(), this.model.getPart("rightLeg").clear(), this.model.getPart("leftLeg").clear())
    };
    this.getPart = function(a) {
        return this.model ? this.model.getPart(a) : null
    };
    this.definedParts = {};
    this.setTextureResolution = function(a, c) {
        for (var b in this.definedParts) this.definedParts[b] && this.definedParts[b].setTextureSize(a, c)
    };
    this.setPart = function(a, c, d) {
        d = d || {};
        var b = this.getPart(a);
        b ? (this.definedParts[a] = b, d.add || b.clear(), b.setTextureSize(d.width ||
            64, d.height || 32), b.setTextureOffset(0, 0, !0), this.__createPart(b, {
            x: 0,
            y: 0,
            z: 0
        }, c)) : (print("no part: " + a), Logger.Log("part " + a + " for render model (base = " + (this.__base || "clear") + ") cannot be created: part " + a + " does not exist", "ERROR"))
    };
    this.__createPart = function(a, c, d) {
        for (var b in d) {
            var f = d[b];
            if (f.coords) {
                var g = {
                    x: parseFloat(f.coords.x) + parseFloat(c.x),
                    y: parseFloat(f.coords.y) + parseFloat(c.y),
                    z: parseFloat(f.coords.z) + parseFloat(c.z)
                };
                f.uv && a.setTextureOffset(f.uv.x, f.uv.y, !0);
                f.size && (f.size.w =
                    f.size.w || 0, a.addBox(g.x - .5 * f.size.x, g.y - .5 * f.size.y, g.z - .5 * f.size.z, f.size.x, f.size.y, f.size.z, f.size.w));
                f.children && this.__createPart(a, g, f.children)
            } else print("RenderAPI Error: some element in part " + a + " has no coords, aborting..."), Logger.Log("RenderAPI Error: some element in part " + a + " has no coords, aborting...", "ERROR")
        }
    };
    this.saveState = function(a, c) {
        EntityRenderGlobalCache.saveRenderAPI(this, a, c)
    };
    this.loadState = function(a, c) {
        return EntityRenderGlobalCache.loadRenderAPI(this, a, c)
    };
    this.saveToNext =
        function(a, c) {
            this.saveState(a);
            this.createBasicModel()
        };
    this.isEmpty = !0;
    this.createBasicModel = function() {
        "raw" == this.__base ? (this.createRaw(), this.isEmpty = !1) : this.__base ? (this.createNative(this.__base), this.isEmpty = !1) : (this.createRaw(), this.clearModel(), this.isEmpty = !0)
    };
    this.__base = a.base;
    a.name ? (this.isEmpty = !this.loadState(a.name)) && this.createBasicModel() : a.empty || this.createBasicModel()
}
var BASIC_NULL_RENDER = new RenderAPI,
    ce_default_entity_render = new RenderAPI;
ce_default_entity_render.setPart("body", [{
    type: "box",
    coords: {
        x: 0,
        y: 16,
        z: 0
    },
    uv: {
        x: 0,
        y: 0
    },
    size: {
        x: 16,
        y: 16,
        z: 16
    }
}], {});

function ModelAPI(a) {
    this.applyTextureResolution = function() {
        var a = this.getTextureResolution();
        this.render && this.render.setTextureResolution(a.w, a.h);
        for (var c in this.animator.animation) this.animator.animation[c].setTextureResolution(a.w, a.h);
        return this
    };
    this.setTexture = function(a) {
        this.texture = a || ce_missing_entity_texture;
        this.applyTextureResolution();
        return this
    };
    this.getTextureObj = function() {
        return this.texture
    };
    this.getTexture = function() {
        return this.texture.getTexture()
    };
    this.getTextureResolution =
        function() {
            return this.texture.getResolution()
        };
    this.isAnimated = !1;
    this.animator = new AnimationHelper;
    this.setRender = function(a) {
        this.isAnimated = !1;
        this.render = a || ce_default_entity_render;
        this.applyTextureResolution();
        return this
    };
    this.createAnimation = function(a, c, d) {
        this.animator.clearAnimation();
        this.animator.setDelay(d);
        d = this.render;
        for (var b = 0; b < a; b++) {
            var f = c(b, this);
            f ? (this.animator.addFrame(f), d = f) : this.animator.addFrame(d)
        }
        this.isAnimated = !0;
        this.applyTextureResolution();
        return this
    };
    this.resetAnimation =
        function(a) {
            this.texture.resetAnimation(a);
            this.animator.resetAnimation(a)
        };
    this.getTextureAndRender = function(a) {
        var b = this.texture.getTexture(a);
        a = this.isAnimated ? this.animator.getFrame(a) : this.render;
        return {
            texture: b,
            render: a.getID()
        }
    };
    a ? (this.setTexture(a.texture), this.setRender(a.render), this.animator.inherit(a.animator), this.isAnimated = a.isAnimated) : (this.setTexture(null), this.setRender(null))
}
var ce_default_entity_model = (new ModelAPI).setTexture(ce_default_entity_texture),
    ce_empty_entity_model = (new ModelAPI).setRender(BASIC_NULL_RENDER),
    ce_missing_entity_model = new ModelAPI;

function ModelWatcher(a, b) {
    this._render = this._texture = null;
    this.model = b;
    this.entity = a;
    this.token = AnimatorToken.genToken();
    this.update = function() {
        var a = this.model.getTextureAndRender(this.token);
        a.texture != this._texture && (this._texture = a.texture, EntityAPI.setSkin(this.entity, this._texture));
        a.render != this._render && (this._render = a.render, EntityAPI.setRender(this.entity, this._render))
    };
    this.resetAnimation = function() {
        this.model.resetAnimation(this.token)
    };
    this.destroy = function() {
        this.remove = !0
    }
}

function EntityAI(a) {
    this.getDefaultPriority = function() {
        return 1
    };
    this.getDefaultName = function() {
        return "basic-entity-ai"
    };
    this.params = {};
    this.setParams = function(a) {
        for (var b in a) this.params[b] = a[b]
    };
    this.executionStarted = function() {};
    this.executionEnded = function() {};
    this.executionPaused = function() {};
    this.executionResumed = function() {};
    this.execute = function() {};
    this.__execute = function() {
        if (0 < this.data.executionTimer && (this.data.executionTimer--, 0 == this.data.executionTimer)) {
            this.finishExecution();
            return
        }
        this.execute()
    };
    this.setExecutionTimer = function(a) {
        this.data.executionTimer = a
    };
    this.removeExecutionTimer = function() {
        this.data.executionTimer = -1
    };
    this.data = {
        executionTimer: -1
    };
    this.isInstance = !1;
    this.entity = this.parent = null;
    this.instantiate = function(a, b) {
        var c = ModAPI.cloneObject(this, !0);
        c.parent = a;
        c.entity = a.entity;
        c.controller = a.AI;
        c.isInstance = !0;
        c.executionName = b;
        return c
    };
    this.aiEntityChanged = function(a) {
        this.entity = a
    };
    this.finishExecution = function() {
        this.controller && this.controller.disableAI(this.executionName)
    };
    this.changeSelfPriority = function(a) {
        this.controller && this.controller.setPriority(this.executionName, a)
    };
    this.enableAI = function(a, b, e) {
        this.controller && this.controller.setPriority(a, b, e)
    };
    this.disableAI = function(a) {
        this.controller && this.controller.setPriority(a)
    };
    this.setPriority = function(a, b) {
        this.controller && this.controller.setPriority(a, b)
    };
    this.getAI = function(a) {
        if (this.controller) return this.controller.getAI(a)
    };
    this.getPriority = function(a) {
        if (this.controller) return this.controller.getPriority(a)
    };
    this.attackedBy = function(a) {};
    this.hurtBy = function(a) {};
    this.projectileHit = function(a) {};
    this.death = function(a) {};
    for (var b in a) this[b] = a[b]
}
var EntityAIIdle = new EntityAI({
    getDefaultPrioriy: function() {
        return 1
    },
    getDefaultName: function() {
        return "idle"
    }
});

function __normalizeAngle(a) {
    for (; a > 2 * Math.PI;) a -= 2 * Math.PI;
    for (; 0 > a;) a += 2 * Math.PI;
    return a
}

function __targetValue(a, b, c) {
    return a + Math.min(Math.max(-c, b - a), c)
}

function __targetAngle(a, b, c) {
    a = __normalizeAngle(a);
    b = __normalizeAngle(b);
    b - Math.PI > a && (b -= 2 * Math.PI);
    a - Math.PI > b && (b += 2 * Math.PI);
    return __targetValue(a, b, c)
}
var EntityAIFollow = new EntityAI({
        data: {
            target: null,
            targetEntity: null,
            movingYaw: 0
        },
        params: {
            speed: .2,
            jumpVel: .45,
            rotateSpeed: .4,
            rotateRatio: .5,
            rotateHead: !0,
            denyY: !0
        },
        setParams: function(a) {
            for (var b in a) this.params[b] = a[b]
        },
        execute: function() {
            this.data.targetEntity && (this.data.target = EntityAPI.getPosition(this.data.targetEntity));
            if (this.data.target) {
                var a = EntityAPI.getMovingVector(this.entity),
                    b = EntityAPI.getMovingAngle(this.entity).yaw,
                    c = EntityAPI.getLookAt(this.entity, this.data.target.x, this.data.target.y,
                        this.data.target.z).yaw,
                    b = b - c;
                this.data.movingYaw || (this.data.movingYaw = c);
                a.xzsize < .5 * this.params.speed && (this.data.movingYaw = __targetAngle(this.data.movingYaw, c + 1.2 * b, this.params.rotateSpeed));
                this.data.movingYaw = __targetAngle(this.data.movingYaw, c, this.params.rotateSpeed * this.params.rotateRatio);
                EntityAPI.moveToAngle(this.entity, {
                    yaw: this.data.movingYaw,
                    pitch: 0
                }, this.params);
                this.params.rotateHead && EntityAPI.setLookAngle(this.entity, this.data.movingYaw, c.pitch)
            }
        }
    }),
    EntityAIPanic = new EntityAI({
        getDefaultPriority: function() {
            return 3
        },
        getDefaultName: function() {
            return "panic"
        },
        params: {
            speed: .22,
            angular_speed: .5
        },
        data: {
            yaw: 0,
            add: 0
        },
        setParams: function(a) {
            for (var b in a) this.params[b] = a[b]
        },
        randomize: function() {
            this.data.add = .5 > Math.random() ? -.5 * Math.random() * this.params.angular_speed : 0
        },
        executionStarted: function() {
            this.data.yaw = Math.random() * Math.PI * 2;
            this.randomize()
        },
        execute: function() {
            0 == WorldAPI.getThreadTime() % 30 && (this.randomize(), EntityAPI.setLookAngle(this.entity, this.data.yaw, 0));
            this.data.yaw += this.data.add;
            EntityAPI.moveToLook(this.entity, {
                speed: this.params.speed,
                denyY: !0,
                jumpVel: .45
            })
        }
    }),
    EntityAIWander = new EntityAI({
        getDefaultPriority: function() {
            return 2
        },
        getDefaultName: function() {
            return "wander"
        },
        params: {
            speed: .08,
            angular_speed: .1,
            delay_weight: .3
        },
        data: {
            yaw: 0,
            add: 0,
            delay: !1,
            _delay: !0
        },
        setParams: function(a) {
            for (var b in a) this.params[b] = a[b]
        },
        randomize: function() {
            Math.random() < this.params.delay_weight ? this.data.delay = !0 : (this.data.delay = !1, this.data.add = .5 > Math.random() ? -.5 * Math.random() * this.params.angular_speed : 0)
        },
        executionStarted: function() {
            this.data.yaw =
                Math.random() * Math.PI * 2;
            this.randomize()
        },
        execute: function() {
            0 == WorldAPI.getThreadTime() % 30 && (this.randomize(), EntityAPI.setLookAngle(this.entity, this.data.yaw, 0));
            this.data.delay || (this.data.yaw += this.data.add, EntityAPI.moveToLook(this.entity, {
                speed: this.params.speed,
                denyY: !0,
                jumpVel: this.data._delay ? 0 : .45
            }));
            this.data._delay = this.data.delay
        }
    }),
    EntityAIAttack = new EntityAI({
        params: {
            attack_damage: 5,
            attack_range: 2.5,
            attack_rate: 12
        },
        data: {
            timer: 0,
            target: null
        },
        execute: function() {
            this.data.target && (EntityAPI.getDistanceToEntity(this.entity,
                this.data.target) < this.params.attack_range ? 0 > this.data.timer-- && (this.data.timer = this.params.attack_rate, EntityAPI.damageEntity(this.data.target, this.params.attack_damage)) : this.data.timer = 0)
        }
    }),
    EntityAISwim = new EntityAI({
        getDefaultPriority: function() {
            return -1
        },
        getDefaultName: function() {
            return "swim"
        },
        params: {
            velocity: .2
        },
        inWater: !1,
        execute: function() {
            if (0 == WorldAPI.getThreadTime() % 5) {
                var a = EntityAPI.getPosition(this.entity),
                    a = getTile_origin(a.x, a.y + .4, a.z);
                this.inWater = 7 < a && 12 > a
            }
            this.inWater && setVelY(this.entity,
                this.params.velocity)
        }
    });

function EntityAIWatcher(a) {
    this.parent = EntityAI;
    this.parent(a);
    this.getDefaultPriority = function() {
        return -1
    };
    this.__execute = function() {
        this.execute()
    }
}
var EntityAIPanicWatcher = new EntityAIWatcher({
        params: {
            panic_time: 200,
            priority_panic: 5,
            priority_default: 1,
            name: "panic"
        },
        data: {
            timer: -1
        },
        hurtBy: function() {
            this.setPriority(this.params.name, this.params.priority_panic);
            this.data.timer = this.params.panic_time
        },
        executionStarted: function() {
            this.setPriority(this.params.name, this.params.priority_default)
        },
        execute: function() {
            0 <= this.data.timer && 0 == --this.data.timer && this.setPriority(this.params.name, this.params.priority_default)
        }
    }),
    EntityAIController = {
        currentPriority: 0,
        loadedAI: {},
        loadedData: {},
        isAILoaded: !1,
        getAITypes: function() {
            return {
                main: {
                    type: EntityAIIdle
                }
            }
        },
        loadEntityAI: function() {
            var a = this.getAITypes();
            this.loadedAI = {};
            for (var b in a) {
                var c = a[b];
                var d = c.type.instantiate(this.parent, b);
                d.setParams(c);
                var e = "undefined" == c.enable + "" ? !0 : c.enable;
                this.loadedAI[b] = {
                    AI: d,
                    priority: c.priority || d.getDefaultPriority(),
                    enabled: e
                };
                e && d.executionStarted()
            }
            for (b in this.loadedData)
                if (c = this.loadedData[b], a = this.loadedAI[b]) a.priority = c.p, a.enabled = c.e, a.data = c.d || {};
            this.refreshPriorities()
        },
        loaded: function() {
            this.isAILoaded ? this.callAIevent("executionResumed") : (this.loadEntityAI(), this.aiLoaded(), this.isAILoaded = !0)
        },
        nativeEntityChanged: function() {
            this.callAIevent("aiEntityChanged", this.parent.entity)
        },
        unloaded: function() {
            this.callAIevent("executionPaused")
        },
        aiLoaded: function() {},
        getAI: function(a) {
            return this.loadedAI[a].AI
        },
        getPriority: function(a) {
            return this.loadedAI[a].priority
        },
        enableAI: function(a, b, c) {
            var d = this.loadedAI[a];
            d && (d.enabled || (d.enabled = !0, d.AI.executionStarted(c)),
                this.setPriority(a, "undefined" == b + "" ? d.priority : b))
        },
        disableAI: function(a) {
            (a = this.loadedAI[a]) && a.enabled && (a.enabled = !1, a.AI.executionEnded(), this.refreshPriorities())
        },
        setPriority: function(a, b) {
            var c = this.loadedAI[a];
            if (c && c.priority != b) {
                var d = c.priority == this.currentPriority;
                c.priority = b;
                this.refreshPriorities();
                d && c.priority != this.currentPriority && c.AI.executionPaused()
            }
        },
        refreshPriorities: function() {
            var a = -1,
                b;
            for (b in this.loadedAI) {
                var c = this.loadedAI[b];
                c.enabled && a < c.priority && (a = c.priority)
            }
            if (a !=
                this.currentPriority)
                for (b in this.loadedAI) c = this.loadedAI[b], c.enabled && (c.priority == a && c.AI.executionResumed(), c.priority == this.currentPriority && c.AI.executionPaused());
            this.currentPriority = a
        },
        callAIevent: function(a, b, c) {
            for (var d in this.loadedAI) {
                var e = this.loadedAI[d];
                if (e.enabled) e.AI[a](b, c)
            }
        },
        update: function() {
            for (var a in this.loadedAI) {
                var b = this.loadedAI[a];
                !b.enabled || b.priority != this.currentPriority && -1 != b.priority || b.AI.__execute()
            }
            this.tick()
        },
        tick: function() {},
        attackedBy: function(a) {
            this.callAIevent("attackedBy",
                a)
        },
        hurtBy: function(a, b) {
            this.callAIevent("hurtBy", a, b)
        },
        death: function(a) {
            this.callAIevent("death", a)
        },
        projectileHit: function(a) {
            this.callAIevent("projectileHit", a)
        },
        save: function() {
            var a = {},
                b;
            for (b in this.loadedAI) {
                var c = this.loadedAI[b];
                a[b] = {
                    e: c.enabled,
                    p: c.priority,
                    d: c.AI.data
                }
            }
            return a
        },
        read: function(a) {
            this.loadedData = a
        }
    },
    EntityDescriptionController = {
        isDynamic: !1,
        getHitbox: function() {
            return {
                w: .99,
                h: .99
            }
        },
        getHealth: function() {
            return 20
        },
        getNameTag: function() {
            return null
        },
        getDrop: function(a) {
            return []
        },
        created: function() {
            var a = this.getHealth();
            Entity.setMaxHealth(this.entity, a);
            Entity.setHealth(this.entity, a)
        },
        loaded: function() {
            var a = this.getHealth();
            Entity.setMaxHealth(this.entity, a);
            a = this.getHitbox();
            Entity.setCollisionSize(this.entity, a.w || 0, a.h || 0);
            (a = this.getNameTag()) ? Entity.setNameTag(this.entity, a): Entity.setNameTag(this.entity, "")
        },
        unloaded: function() {},
        removed: function() {},
        getNumberFromData: function(a, b) {
            return a ? "number" == typeof a ? a : a.min && a.max ? parseInt((a.max - a.min + 1) * Math.random()) +
                a.min : a.length ? a[parseInt(a.length * Math.random())] : b : b
        },
        provideDrop: function(a) {
            a = this.getDrop(a);
            var b = EntityAPI.getPosition(this.entity),
                c = function(a, c, d) {
                    EntityAPI.setVelocity(Level.dropItem(b.x, b.y + .3, b.z, 0, a, c, d), .4 * Math.random() - .2, .3 * Math.random(), .4 * Math.random() - .2)
                },
                d;
            for (d in a) {
                var e = a[d],
                    f = e.chance || 1;
                if (e.id && Math.random() < f) {
                    var f = this.getNumberFromData(e.count, 1),
                        g = this.getNumberFromData(e.data, 0);
                    if (e.separate)
                        for (var h = 0; h < f; h++) c(e.id, 1, g);
                    else c(e.id, f, g)
                }
            }
        },
        death: function(a) {
            this.provideDrop(a)
        },
        update: function() {},
        save: function() {},
        read: function() {}
    },
    EntityVisualController = {
        modelWatchers: {},
        modelWatcherStack: [],
        getModels: function() {
            return {
                main: ce_default_entity_model
            }
        },
        createModelWatchers: function() {
            this.modelWatchers = {};
            var a = this.getModels();
            a.main || (a.main = ce_default_entity_model);
            for (var b in a) this.modelWatchers[b] = new ModelWatcher(this.entity, a[b])
        },
        getModelWatcher: function(a) {
            return this.modelWatchers[a]
        },
        setModel: function(a, b) {
            var c = this.getModelWatcher(a);
            c ? (this.modelWatcherStack ||
                (this.modelWatcherStack = []), 0 <= b ? this.modelWatcherStack.unshift({
                    name: a,
                    ticks: b
                }) : this.modelWatcherStack = [{
                    name: a,
                    ticks: -1
                }], c.resetAnimation()) : Logger.Log("cannot set entity model: no model watcher for '" + a + "' found.", "ERROR")
        },
        resetModel: function() {
            this.modelWatcherStack = []
        },
        resetAllAnimations: function() {
            for (var a in this.modelWatchers) this.modelWatchers[a].resetAnimation()
        },
        getCurrentModelName: function() {
            for (var a = this.modelWatcherStack[0]; a && 0 == a.ticks;) a = this.modelWatcherStack.shift();
            return a ?
                a : {
                    name: "main",
                    ticks: -1
                }
        },
        loaded: function() {
            this.createModelWatchers()
        },
        update: function() {
            var a = this.getCurrentModelName(),
                b = this.getModelWatcher(a.name);
            b && b.update();
            a.ticks--
        },
        save: function() {
            return this.modelWatcherStack
        },
        read: function(a) {
            this.modelWatcherStack = a || []
        }
    },
    EntityEventController = {
        update: function() {
            this.tick()
        },
        tick: function() {},
        removed: function() {},
        created: function(a) {},
        loaded: function() {},
        unloaded: function() {},
        attackedBy: function(a) {},
        hurtBy: function(a, b) {},
        death: function(a) {},
        projectileHit: function(a) {},
        save: function() {},
        read: function() {}
    },
    CustomEntityConfig = {},
    ENTITY_UNLOAD_DISTANCE = 56;

function CustomEntity(a) {
    this.nameId = a;
    this.controllers = {};
    this.isInstance = !1;
    this.entity = null;
    this.unloadedTime = this.age = 0;
    this.realPosition = null;
    this.__base_type = 28;
    UpdatableSaver.registerPrototype("_CUSTOM_MOB:" + this.nameId, this);
    this.addController = function(a, c) {
        var b = ModAPI.cloneObject(c, !0);
        b.parent = null;
        b.__controller_name = a;
        this[a] = b;
        this.controllers[a] = b;
        return this
    };
    this.customizeController = function(a, c) {
        if (this[a]) {
            var b = ModAPI.cloneObject(c, !0),
                e = this[a];
            for (a in b) e[a] = b[a]
        } else Logger.Log("Cannot customize entity controller " +
            a + ": no such defined", "ERROR")
    };
    this.customizeEvents = function(a) {
        this.customizeController("event", a)
    };
    this.customizeDescription = function(a) {
        this.customizeController("description", a)
    };
    this.customizeVisual = function(a) {
        this.customizeController("visual", a)
    };
    this.customizeAI = function(a) {
        this.customizeController("AI", a)
    };
    this.setBaseType = function(a) {
        this.isInstance ? Logger.Log("cannot set base entity type on entity in world", "ERROR") : this.__base_type = a
    };
    this.callControllerEvent = function() {
        var a = arguments[0],
            c = [];
        for (e in arguments) 0 < e && c.push(arguments[e]);
        for (var d in this.controllers) {
            var e = this.controllers[d];
            e[a] && e[a].apply(e, c)
        }
    };
    this.setNativeEntity = function(a) {
        this.entity = parseInt(a);
        for (var b in this.controllers) this.controllers[b].entity = parseInt(a);
        this.callControllerEvent("nativeEntityChanged")
    };
    this.recreateEntity = function() {
        this.realPosition && (this.lockRemovalHook = !0, Entity.remove(this.entity), this.lockRemovalHook = !1, this.setNativeEntity(Level.spawnMob(this.realPosition.x, this.realPosition.y,
            this.realPosition.z, this.__base_type)), this.isLoaded || (this.isLoaded = !0, this.callControllerEvent("loaded")))
    };
    this.getPlayerDistance = function() {
        var a = getPlayerX() - this.realPosition.x,
            c = getPlayerZ() - this.realPosition.z;
        return Math.sqrt(a * a + c * c)
    };
    this.denyDespawn = function() {
        this.isNaturalDespawnAllowed = !1;
        this.isDespawnDenied = !0
    };
    this.allowNaturalDespawn = function() {
        this.isNaturalDespawnAllowed = !0;
        this.isDespawnDenied = !1
    };
    this.handleUnloadedState = function() {
        this.unloadedTime++;
        0 == this.age % 200 && (!this.isDespawnDenied &&
            CustomEntityConfig.despawn_unloaded_entities && this.unloadedTime > CustomEntityConfig.unloaded_despawn_time_in_secs ? this.destroy() : this.getPlayerDistance() < ENTITY_UNLOAD_DISTANCE && (this.isNaturalDespawnAllowed ? this.destroy() : this.isDestroyed || this.recreateEntity()))
    };
    this.update = function() {
        if (0 == this.age % 20) {
            var a = EntityAPI.getPosition(this.entity),
                c = 0 < a.y;
            c && (this.realPosition = a);
            this.isLoaded && !c && this.callControllerEvent("unloaded");
            !this.isLoaded && c && this.callControllerEvent("loaded");
            (this.isLoaded =
                c) ? this.unloadedTime = 0: this.handleUnloadedState()
        }
        if (this.isLoaded)
            for (var d in this.controllers) this.controllers[d].update();
        this.age++
    };
    this.instantiate = function(a) {
        a = parseInt(a);
        var b = ModAPI.cloneObject(this, !0);
        b.entity = a;
        b.realPosition = EntityAPI.getPosition(a);
        b.isInstance = !0;
        b.isLoaded = !1;
        for (var d in b.controllers) {
            var e = b.controllers[d];
            e.parent = b;
            e.entity = a;
            b[d] = e
        }
        MobRegistry.registerUpdatableAsEntity(b);
        UpdatableAPI.addUpdatable(b);
        return b
    };
    this.lockRemovalHook = !1;
    this.registerRemoval =
        function() {
            this.lockRemovalHook || (this.isLoaded = !1, EntityAPI.getXZPlayerDis(this.entity) > ENTITY_UNLOAD_DISTANCE ? this.callControllerEvent("unloaded") : this.destroy())
        };
    this.destroy = function() {
        this.remove = this.isDestroyed = !0;
        this.callControllerEvent("removed");
        Entity.remove(this.entity);
        this.callControllerEvent("unloaded")
    };
    this.read = function(a) {
        var b = this.isInstance ? this : this.instantiate(a.entity);
        b.entity = a.entity || null;
        b.age = a.age || 0;
        b.unloadedTime = a.unloaded || 0;
        b.realPosition = a.rp || null;
        for (var d in a.controllers) {
            var e =
                b[d];
            e ? (e.read(a.controllers[d]), e.entity = b.entity) : Logger.Log("Entity controller is missing " + d + " while reading entity data", "WARNING")
        }
        return !0
    };
    this.save = function() {
        var a = {
                entity: this.entity,
                age: this.age,
                unloaded: this.unloadedTime,
                controllers: {},
                rp: this.realPosition
            },
            c;
        for (c in this.controllers) a.controllers[c] = this.controllers[c].save(c);
        return a
    }
}
Callback.addCallback("CoreConfigured", function(a) {
    CustomEntityConfig = a.access("perfomance.entity")
});
var MobRegistry = {
    customEntities: {},
    loadedEntities: [],
    registerEntity: function(a) {
        var b = new CustomEntity(a);
        b.addController("event", EntityEventController);
        b.addController("description", EntityDescriptionController);
        b.addController("visual", EntityVisualController);
        b.addController("AI", EntityAIController);
        return this.customEntities[a] = b
    },
    registerUpdatableAsEntity: function(a) {
        for (var b in this.loadedEntities)
            if (this.loadedEntities[b].entity == a.entity) {
                Logger.Log("Dublicate entities updatables loaded for " +
                    a.entity + ", removing second one", "WARNING");
                a.remove = !0;
                return
            }
        this.loadedEntities.push(a)
    },
    spawnEntityAsPrototype: function(a, b, c) {
        var d = this.customEntities[a];
        d || Logger.Log("Cannot spawn custom entity: type " + a + "is not found", "ERROR");
        a = Level.spawnMob(b.x, b.y, b.z, d.__base_type);
        d = d.instantiate(a);
        d.callControllerEvent("created", c);
        d.update();
        return d
    },
    getEntityUpdatable: function(a) {
        a = parseInt(a);
        for (var b in this.loadedEntities)
            if (this.loadedEntities[b].entity == a) return this.loadedEntities[b];
        return null
    },
    registerNativeEntity: function(a) {},
    registerEntityRemove: function(a) {
        (a = this.getEntityUpdatable(a)) && a.registerRemoval()
    },
    resetEngine: function() {
        this.loadedEntities = []
    }
};
Callback.addCallback("LevelSelected", function() {
    MobRegistry.resetEngine()
});
Callback.addCallback("EntityAdded", function(a) {
    MobRegistry.registerNativeEntity(a)
});
Callback.addCallback("EntityRemoved", function(a) {
    MobRegistry.registerEntityRemove(a)
});
Callback.addCallback("PlayerAttack", function(a, b) {
    var c = MobRegistry.getEntityUpdatable(b);
    c && c.callControllerEvent("attackedBy", a)
});
Callback.addCallback("EntityDeath", function(a, b) {
    var c = MobRegistry.getEntityUpdatable(a);
    c && c.callControllerEvent("death", b)
});
Callback.addCallback("EntityHurt", function(a, b, c) {
    (b = MobRegistry.getEntityUpdatable(b)) && b.callControllerEvent("hurtBy", a, c)
});
Callback.addCallback("ProjectileHitEntity", function(a, b) {
    var c = MobRegistry.getEntityUpdatable(b);
    c && c.callControllerEvent("projectileHit", a)
});
var ENTITY_MIN_SPAWN_DIS = 32,
    ENTITY_MAX_SPAWN_DIS = 63,
    EntitySpawnRegistry = {
        spawnData: [],
        registerSpawn: function(a, b, c, d) {
            c || (c = function() {
                return parseInt(3 * Math.random() + 1)
            });
            this.spawnData.push({
                type: a,
                rarity: b,
                condition: c,
                denyNaturalDespawn: d
            })
        },
        getRandomSpawn: function(a) {
            var b = this.spawnData[parseInt(Math.random() * this.spawnData.length)];
            if (b && Math.random() < b.rarity * this.spawnData.length * a) return b
        },
        getRandPosition: function() {
            var a = Math.random() * Math.PI * 2,
                b = Math.random() * (ENTITY_MAX_SPAWN_DIS - ENTITY_MIN_SPAWN_DIS) +
                ENTITY_MIN_SPAWN_DIS;
            return {
                x: getPlayerX() + Math.sin(a) * b,
                z: getPlayerZ() + Math.cos(a) * b
            }
        },
        executeSpawn: function(a, b) {
            b = b || this.getRandPosition();
            var c = {
                    y: -1,
                    accessY: function() {
                        -1 == this.y && (this.y = WorldGenerationUtils.findLowSurface(b.x, b.z).y + 1);
                        return this.y
                    },
                    condition: a.condition
                },
                d = c.condition(b.x, b.z);
            if (0 < d)
                for (b.y = c.accessY(), c = 0; c < d; c++) {
                    var e = EntityAPI.spawnCustomAtCoords(a.type, b);
                    e.allowNaturalDespawn(!a.denyNaturalDespawn);
                    EntityAPI.setVelocity(e.entity, Math.random() - .5, 0, Math.random() - .5)
                }
        },
        counter: 0,
        tick: function() {
            if (0 == this.counter++ % 100) {
                var a = this.getRandomSpawn(5 / 60);
                a && this.executeSpawn(a)
            }
        },
        onChunkGenerated: function(a, b) {
            for (var c = 0; c < this.spawnData.length; c++) {
                var d = {
                        x: 16 * (a + Math.random()),
                        z: 16 * (b + Math.random())
                    },
                    e = this.getRandomSpawn(2 / this.spawnData.length);
                e && this.executeSpawn(e, d)
            }
        }
    };
Callback.addCallback("tick", function() {
    EntitySpawnRegistry.tick()
});
Callback.addCallback("GenerateChunk", function(a, b) {
    EntitySpawnRegistry.onChunkGenerated(a, b)
});

function PlayerInventory(a, b) {
    this.parent = Container;
    this.parent();
    this.slotMap = {};
    this.isImportedFromDynamicSource = !1;
    this.refreshInv = function() {
        if (PlayerInventorySlotSource.updating) {
            for (var a = 0; 45 > a; a++) 9 > a ? this.slots["hotbar" + a] = PlayerInventorySlotSource.getSource(a) : this.slots["inv" + (a - 9)] = PlayerInventorySlotSource.getSource(a);
            this.isImportedFromDynamicSource = !0
        } else {
            for (a = 0; 45 > a; a++) {
                var b = 9 > a ? this.getSlot("hotbar" + a) : this.getSlot("inv" + (a - 9));
                b.id = Player.getInventorySlot(a);
                b.count = Player.getInventorySlotCount(a);
                b.data = Player.getInventorySlotData(a);
                this.slotMap[a] = {
                    id: b.id,
                    count: b.count,
                    data: b.data
                }
            }
            this.isImportedFromDynamicSource = !1
        }
        return this
    };
    this.refreshArm = function() {
        for (var a = 0; 4 > a; a++) {
            var b = this.getSlot("arm" + a);
            b.id = Player.getArmorSlot(a);
            b.count = 0 < b.id ? 1 : 0;
            b.data = Player.getArmorSlotDamage(a);
            this.slotMap[a + 128] = {
                id: b.id,
                count: b.count,
                data: b.data
            }
        }
        return this
    };
    this.applyInv = function() {
        for (var a = 0; 45 > a; a++)
            if (9 > a) this.getSlot("hotbar" + a);
            else {
                var b = this.getSlot("inv" + (a - 9));
                var e = this.slotMap[a];
                b.id == e.id && b.count == e.count && b.data == e.data || Player.setInventorySlot(a, b.id, b.count, b.data)
            }
        return this
    };
    this.applyArm = function() {
        for (var a = 0; 4 > a; a++) {
            var b = this.getSlot("arm" + a),
                e = this.slotMap[a + 128];
            b.id == e.id && b.count == e.count && b.data == e.data || Player.setArmorSlot(a, b.id, b.data)
        }
        return this
    };
    this.addItem = function(a, b, e, f) {
        b = this.addItemWithOverloadAmount(a, b, e, f);
        0 < b && EntityAPI.setVelocity(Level.dropItem(getPlayerX(), getPlayerY(), getPlayerZ(), 0, a, b, e), 0, 0, 0);
        return this
    };
    this.addItemWithOverloadAmount =
        function(a, b, e, f) {
            for (var c = Math.min(this.getFreePlaceAmountForItem(a, e), b), d = c; 0 < d;) {
                var k = Math.min(64, d);
                Player.addItemInventory(a, k, e);
                d -= k
            }
            f && this.refreshInv();
            return b - c
        };
    this.getFreePlaceAmountForItem = function(a, b) {
        for (var c = 0, d = ItemRegistry.getMaxStack(a), g = 0; 36 > g; g++) {
            var h = this.getSlot("inv" + g);
            if (0 == h.id || h.id == a && (h.data == b || -1 == b)) c += d - h.count
        }
        return c
    };
    this.getItem = function(a, b, e, f) {
        for (var c = 0, d = 0; 36 > d; d++)
            if (slot = this.getSlot("inv" + d), slot.id == a && (slot.data == e || -1 == e)) {
                var k = Math.min(slot.count,
                    b);
                b -= k;
                c += k;
                slot.count -= k;
                0 == slot.count && (slot.id = slot.data = 0)
            }
        f || this.applyInv();
        return c
    };
    this.getFullItem = function(a, b, e, f) {
        a = {
            id: a,
            data: e,
            count: 0
        };
        for (e = 0; 36 > e; e++)
            if (slot = this.getSlot("inv" + e), slot.id == a.id && (slot.data == a.data || -1 == a.data)) {
                var c = Math.min(slot.count, b);
                b -= c;
                a.count += c;
                slot.count -= c;
                a.data = slot.data;
                0 == slot.count && (slot.id = slot.data = 0)
            }
        f || this.applyInv();
        return a
    };
    this.getSelectedId = function() {
        return Player.getSelectedSlotId()
    };
    this.getSelectedName = function() {
        return "hotbar" +
            this.getSelectedId()
    };
    this.getSelectedSlot = function() {
        return this.getSlot(this.getSelectedName())
    };
    this.setSelectionPos = function(a) {
        Player.setSelectedSlotId(a || 0)
    }
}
var PlayerAPI = {
        get: function() {
            return getPlayerEnt()
        },
        getNameForEnt: function(a) {
            return Player.getName(a)
        },
        getName: function() {
            return this.getNameForEnt(this.get())
        },
        getDimension: function() {
            return Player.getDimension()
        },
        isPlayer: function(a) {
            return Player.isPlayer(a)
        },
        getPointed: function() {
            var a = {
                x: Player.getPointedBlockX(),
                y: Player.getPointedBlockY(),
                z: Player.getPointedBlockZ(),
                side: Player.getPointedBlockSide()
            };
            return {
                pos: a,
                block: WorldAPI.getBlock(a.x, a.y, a.z),
                entity: Player.getPointedEntity(),
                vec: {
                    x: Player.getPointedVecX(),
                    y: Player.getPointedVecY(),
                    z: Player.getPointedVecZ()
                }
            }
        },
        getInventory: function(a, b, c) {
            b = new PlayerInventory(b, c);
            "inventory" != a && "all" != a || b.refreshInv();
            "armor" != a && "all" != a || b.refreshArm();
            return b
        },
        addItemToInventory: function(a, b, c) {
            this.getInventory("inventory").addItem(a, b, c)
        },
        getCarriedItem: function(a, b) {
            return UnlimitedAPIAccess.getCarriedItem(a)
        },
        setCarriedItem: function(a, b, c, d, e) {
            return UnlimitedAPIAccess.setPlayerCarriedItem(a, b, c, d, e)
        },
        decreaseCarriedItem: function(a) {
            "undefined" == a + "" && (a =
                1);
            var b = this.getCarriedItem(!0);
            this.setCarriedItem(b.id, b.count - a, b.data, b.enchant)
        },
        setPosition: function(a, b, c) {
            setPosition(this.get(), a, b, c)
        },
        getPosition: function() {
            return {
                x: Player.getX(),
                y: Player.getY(),
                z: Player.getZ()
            }
        },
        addPosition: function(a, b, c) {
            var d = this.getPosition();
            this.setPosition(d.x + a, d.y + b, d.z + c)
        },
        setVelocity: function(a, b, c) {
            var d = this.get();
            setVelX(d, a);
            setVelY(d, b);
            setVelZ(d, c)
        },
        getVelocity: function() {
            var a = this.get();
            return {
                x: Entity.getVelX(a),
                y: Entity.getVelY(a),
                z: Entity.getVelZ(a)
            }
        },
        addVelocity: function(a, b, c) {
            var d = this.getVelocity();
            this.setVelocity(d.x + a, d.y + b, d.z + c)
        },
        experience: function() {
            return {
                get: this.getExperience,
                set: this.setExperience,
                add: this.addExperience
            }
        },
        getExperience: function() {
            return Player.getExp()
        },
        setExperience: function(a) {
            Player.getExp(a)
        },
        addExperience: function(a) {
            Player.addExp(a)
        },
        level: function() {
            return {
                get: this.getLevel,
                set: this.setLevel,
                add: this.addLevel
            }
        },
        getLevel: function() {
            return Player.getLevel()
        },
        setLevel: function(a) {
            Player.setLevel(a)
        },
        addLevel: function(a) {
            this.setLevel(this.getLevel() +
                a)
        },
        flying: function() {
            return {
                set: this.setFlying,
                get: this.getFlying,
                getEnabled: this.getFlyingEnabled,
                setEnabled: this.setFlyingEnabled
            }
        },
        getFlyingEnabled: function() {
            return Player.canFly()
        },
        setFlyingEnabled: function(a) {
            Player.setCanFly(a)
        },
        getFlying: function() {
            return Player.isFlying()
        },
        setFlying: function(a) {
            Player.setFlying(a)
        },
        exhaustion: function() {
            return {
                get: this.getExhaustion,
                set: this.setExhaustion
            }
        },
        getExhaustion: function() {
            return Player.getExhaustion()
        },
        setExhaustion: function(a) {
            Player.setExhaustion(a)
        },
        hunger: function() {
            return {
                get: this.getHunger,
                set: this.setHunger
            }
        },
        getHunger: function() {
            return Player.getHunger()
        },
        setHunger: function(a) {
            Player.setHunger(a)
        },
        saturation: function() {
            return {
                get: this.getSaturation,
                set: this.setSaturation
            }
        },
        getSaturation: function() {
            return Player.getSaturation()
        },
        setSaturation: function(a) {
            Player.setSaturation(a)
        },
        health: function() {
            return {
                get: this.getHealth,
                set: this.setHealth
            }
        },
        getHealth: function() {
            return Player.getHealth()
        },
        setHealth: function(a) {
            Player.setHealth(a)
        },
        score: function() {
            return {
                get: this.getScore
            }
        },
        getScore: function() {
            return Player.getScore()
        }
    },
    ANIMATION_BASE_ENTITY = 15 < MCPE_VERSION.main ? EntityType.SQUID : EntityType.RABBIT,
    AnimationRegistry = {
        animationList: [],
        resetEngine: function() {
            this.animationList = []
        },
        registerAnimation: function(a) {
            this.animationList.push(a)
        },
        getEntityArray: function() {
            var a = [];
            try {
                for (var b in this.animationList) {
                    var c = this.animationList[b];
                    c.entity && !c.remove && a.push(parseInt(c.entity))
                }
            } catch (d) {
                print(d)
            }
            return {
                entites: a
            }
        },
        onAttack: function(a) {
            for (var b in this.animationList) {
                var c =
                    this.animationList[b];
                c.entity != a || c.remove || (preventDefault(), c.onAttack())
            }
        }
    };
Callback.addCallback("PlayerAttack", function(a, b) {
    AnimationRegistry.onAttack(b)
});

function AnimationBase(a, b, c) {
    this.setPos = function(a, b, c) {
        b += this.yOffset;
        this.coords = {
            x: a,
            y: b,
            z: c
        };
        if (this.entity) {
            var d = this.entity;
            MainThread.push(function() {
                setPosition(d, a, b, c)
            })
        }
    };
    this.yOffset = 0;
    this.description = {
        hasModel: !1
    };
    this.entity = null;
    this.setPos(a, b, c);
    this.load = function() {
        this.__age = 0;
        UpdatableAPI.addUpdatable(this)
    };
    this.toJSON = function() {
        return null
    };
    this.loadCustom = function(a) {
        this.tick = a;
        this.load()
    };
    this.getAge = function() {
        return this.__age || 0
    };
    this.refresh = function(a) {
        this.visualUpdate();
        a && (this.__refresh = !0)
    };
    this.describe = function(a, b) {
        for (var c in a) this.description[c] = a[c];
        this.description.hasModel = !0;
        this.description.firmRotation = 17 > MCPE_VERSION.main && this.description.firmRotation;
        this.refresh(b)
    };
    this.getRenderAPI = function(a) {
        this.description.renderAPI || (this.description.renderAPI = new RenderAPI(a));
        return this.description.renderAPI
    };
    this.destroy = function() {
        Entity.remove(this.entity);
        this.remove = !0
    };
    this.visualUpdate = function() {
        this.description.skin && EntityAPI.setSkin(this.entity,
            this.description.skin);
        this.description.renderAPI ? EntityAPI.setRender(this.entity, this.description.renderAPI.getID()) : this.description.render && EntityAPI.setRender(this.entity, this.description.render)
    };
    this.checkEntity = function() {
        var a = this;
        MainThread.push(function() {
            a.__checkEntity()
        })
    };
    this.__checkEntity = function() {
        if (this.description.hasModel && !this.remove && (this.__refresh || !EntityAPI.isExist(this.entity))) {
            var a = this.entity;
            this.entity = EntityAPI.spawn(this.coords.x, this.coords.y + this.yOffset, this.coords.z,
                ANIMATION_BASE_ENTITY);
            Entity.setAnimalAge(this.entity, 0);
            this.visualUpdate();
            this.description.hitbox ? EntityAPI.setHitbox(this.entity, this.description.hitbox.width, this.description.hitbox.height) : EntityAPI.setHitbox(this.entity, 0, 0);
            EntityAPI.setMobile(this.entity, !1);
            try {
                Entity.setMaxHealth(this.entity, 9999), EntityAPI.setHealth(this.entity, 9999)
            } catch (e) {}
            Entity.remove(a);
            this.__refresh = !1
        }
    };
    this.update = function() {
        if (!this.remove) {
            this.tick();
            if (0 == this.__age % 10 && this.description.firmRotation) this.__refresh = !0, this.checkEntity();
            else if (0 == this.__age % 20) {
                this.checkEntity();
                try {
                    EntityAPI.setHealth(this.entity, 9999)
                } catch (d) {}
            }
            this.__age++
        }
    };
    this.onEngineReset = function() {
        this.remove = !0
    };
    this.tick = function() {};
    this.onAttack = function() {};
    AnimationRegistry.registerAnimation(this)
}
SaverAPI.addSavesScope("native_animation", function(a) {
    var b = a.entites;
    AnimationRegistry.resetEngine();
    UpdatableAPI.addUpdatable({
        countdown: 60,
        update: function() {
            if (0 < this.countdown--)
                for (var a in b) Entity.remove(b[a]);
            else this.remove = !0
        }
    })
}, function() {
    return AnimationRegistry.getEntityArray()
});

function AnimationText(a, b, c, d) {
    this.parent = AnimationBase;
    this.parent(a, b, c);
    this.setText = function(a) {
        this.text = a || ""
    };
    this.setText(d);
    this.describe({
        renderAPI: BASIC_NULL_RENDER
    });
    this.tick = function() {
        EntityAPI.setNameTag(this.entity, this.text)
    }
}
var USE_ALTERNATIVE_ITEM_MODEL = !1;

function AnimationItem(a, b, c) {
    this.parent = AnimationBase;
    this.parent(a, b, c);
    this.describeItemDefault = function(a, b) {
        a.size || (a.size = .5);
        var c = new RenderAPI({
                empty: !0
            }),
            d = "__item" + a.id + "|" + a.count + "|" + a.data + "|" + a.size + "|" + a.rotation + "|" + !a.notRandomize;
        b ? d += "|" + b.x + "|" + b.y + "|" + b.z : b = {
            x: 0,
            y: 0,
            z: 0
        };
        if (!c.loadState(d)) {
            c.createBasicModel();
            var e = [],
                k = function(a, b, c) {
                    return {
                        x: -7.5 + a,
                        y: c,
                        z: -7.5 + b
                    }
                };
            "x" == a.rotation && (k = function(a, b, c) {
                return {
                    x: c,
                    y: -7.5 + b,
                    z: -7.5 + a
                }
            });
            "z" == a.rotation && (k = function(a, b, c) {
                return {
                    x: -7.5 +
                        a,
                    y: -7.5 + b,
                    z: c
                }
            });
            for (var m = 0; m < a.count; m++) {
                var l = 0,
                    n = 0;
                0 < m && !a.notRandomize && (l = 5 * Math.random() - 2.5, n = 5 * Math.random() - 2.5);
                for (var r = 0; 16 > r; r++)
                    for (var p = 0; 16 > p; p++) {
                        var q = k(l + r, n + p, m - a.count / 2);
                        e.push({
                            type: "box",
                            uv: {
                                x: 1 - (1 + r) / 16 * 2048,
                                y: p / 16 * 2048
                            },
                            size: {
                                x: 1,
                                y: 1,
                                z: 1,
                                w: .5 * (a.size - 1)
                            },
                            coords: {
                                x: q.x * a.size + 16 * b.x,
                                y: q.y * a.size + 25 - 16 * b.y,
                                z: q.z * a.size - 16 * b.z
                            }
                        })
                    }
            }
            c.setPart("body", e, {
                width: 2048,
                height: 2048
            });
            c.saveState(d)
        }
        this.describe({
            renderAPI: c,
            skin: ItemIconSource.getIconName(a.id, a.data)
        })
    };
    this.describeItemAlternative =
        function(a, b) {
            a.size || (a.size = .5);
            var c = new RenderAPI({
                    empty: !0
                }),
                d = "__item" + a.id + "|" + a.count + "|" + a.data + "|" + a.size + "|" + a.rotation + "|" + !a.notRandomize;
            b ? d += "|" + b.x + "|" + b.y + "|" + b.z : b = {
                x: 0,
                y: 0,
                z: 0
            };
            if (!c.loadState(d)) {
                c.createBasicModel();
                for (var e = [], k = parseInt(16 * a.size), m = Math.min(64, k), l = k / 16, n = 0; n < a.count; n++) {
                    var r = 0,
                        p = 0;
                    0 < n && !a.notRandomize && (r = 5 * Math.random() - 2.5, p = 5 * Math.random() - 2.5);
                    for (var q = 0; q <= l; q += l / m) e.push({
                        type: "box",
                        uv: {
                            x: 0,
                            y: 0
                        },
                        size: {
                            x: k,
                            y: k,
                            z: 0
                        },
                        coords: {
                            x: r + 16 * b.x,
                            y: 25 + p - 16 * b.y,
                            z: (n - .5 - a.count / 2) * l + q - 16 * b.z
                        }
                    })
                }
                c.setPart("body", e, {
                    width: k,
                    height: k
                });
                c.saveState(d)
            }
            this.describe({
                renderAPI: c,
                skin: ItemIconSource.getIconName(a.id, a.data)
            })
        };
    this.describeItem = this.describeItemDefault;
    USE_ALTERNATIVE_ITEM_MODEL && (this.describeItem = this.describeItemAlternative);
    this.tick = function() {}
}
Callback.addCallback("CoreConfigured", function(a) {
    USE_ALTERNATIVE_ITEM_MODEL = a.access("util.alternative_item_model")
});

function EntityInventory(a, b, c) {
    this.parent = Container;
    this.parent();
    this.entity = a;
    this.refreshArm = function() {
        for (var a = 0; 4 > a; a++) {
            var b = this.getSlot("arm" + a);
            b.id = Entity.getArmor(this.entity, a);
            b.data = Entity.getArmorDamage(this.entity, a);
            b.count = 1 < b.id ? 1 : 0
        }
    };
    this.refreshCarried = function() {
        Logger.Log("cannot refresh carried slot for " + this.entity + ": entity carried item cannot be accessed", "WARNING")
    };
    this.refreshItem = function() {
        var a = this.getSlot("item");
        a.id = Entity.getItemEntityId(this.entity);
        a.count =
            Entity.getItemEntityCount(this.entity);
        a.data = Entity.getItemEntityData(this.entity)
    };
    this.applyArm = function() {
        for (var a = 0; 4 > a; a++) {
            var b = this.getSlot("arm" + a);
            Entity.setArmor(this.entity, a, b.id, b.data)
        }
    };
    this.applyCarried = function() {
        var a = this.getSlot("carried");
        UnlimitedAPIAccess.setCarriedItem(this.entity, a.id, a.count, a.data)
    };
    this.applyItem = function() {
        Logger.Log("cannot apply item slot to " + this.entity + ": item entity cannot be changed", "WARNING")
    };
    this.refresh = function() {
        this.refreshArm();
        64 ==
            EntityAPI.getType(this.ent) && this.refreshItem()
    };
    this.apply = function() {
        this.applyArm();
        this.applyCarried()
    }
}
var __RAD_TO_DEGREES = 180 / Math.PI;

function __radToDegrees(a) {
    return a * __RAD_TO_DEGREES
}

function __degreesToRad(a) {
    return a / __RAD_TO_DEGREES
}
var EntityAPI = {
    _AI: {},
    getAll: function() {
        return Entity.getAll()
    },
    getAllJS: function() {
        for (var a = this.getAll(), b = [], c = 0; c < a.length; c++) b.push(a[c]);
        return b
    },
    EXTRA_DATA_PREFIX: "core.engine.",
    getExtra: function(a, b) {
        return Entity.getExtraData(a, this.EXTRA_DATA_PREFIX + b)
    },
    putExtra: function(a, b, c) {
        Entity.setExtraData(a, this.EXTRA_DATA_PREFIX + b, c)
    },
    getExtraJson: function(a, b) {
        try {
            return JSON.parse(this.getExtra(a, b)) || {}
        } catch (c) {
            return {}
        }
    },
    putExtraJson: function(a, b, c) {
        this.putExtra(a, b, JSON.stringify(c))
    },
    addEffect: function(a, b, c, d, e, f) {
        try {
            Entity.addEffect(a, b, c, d, e, f)
        } catch (g) {}
    },
    clearEffect: function(a, b) {
        Entity.removeEffect(a, b)
    },
    clearEffects: function(a) {
        Entity.removeAllEffects(a)
    },
    damageEntity: function(a, b) {
        var c = MobEffect.harm,
            d = this.getType(a);
        if (d == EntityType.ZOMBIE || d == EntityType.ZOMBIE_VILLAGER || d == EntityType.SKELETON || 48 == d) c = MobEffect.heal;
        var e = Entity.getHealth(a) - b + 6;
        1 > e ? (e = 1, this.addEffect(a, c, 1, 1)) : this.addEffect(a, c, 1, 0);
        MainThread.push(function() {
            Entity.setHealth(a, e)
        })
    },
    healEntity: function(a,
        b) {
        var c = Entity.getHealth(a) + b,
            d = Entity.getMaxHealth(a);
        Entity.setHealth(a, Math.min(c, d))
    },
    getType: function(a) {
        return EntityDataRegistry.getType(a) || Entity.getEntityTypeId(a)
    },
    setHitbox: function(a, b, c) {
        Entity.setCollisionSize(a, b, c)
    },
    isExist: function(a) {
        return 0 < Entity.getY(a)
    },
    spawn: function(a, b, c, d, e) {
        return Level.spawnMob(a, b, c, d, e)
    },
    spawnCustom: function(a, b, c, d, e) {
        return this.spawnCustomAtCoords(a, {
            x: b,
            y: c,
            z: d
        }, e)
    },
    spawnCustomAtCoords: function(a, b, c) {
        return MobRegistry.spawnEntityAsPrototype(a,
            b, c)
    },
    spawnAtCoords: function(a, b, c) {
        return this.spawn(a.x, a.y, a.z, b, c)
    },
    remove: function(a) {
        Entity.remove(a)
    },
    getCustom: function(a) {
        return MobRegistry.getEntityUpdatable(a)
    },
    getAge: function(a) {
        return Entity.getAnimalAge(a)
    },
    setAge: function(a, b) {
        return Entity.setAnimalAge(a, b)
    },
    getSkin: function(a) {
        return Entity.getMobSkin(a)
    },
    setSkin: function(a, b) {
        MainThread.push(function() {
            Entity.setMobSkin(a, b)
        })
    },
    setTexture: function(a, b) {
        this.setSkin(a, b.getTexture())
    },
    getRender: function(a) {
        return Entity.getRenderType(a)
    },
    setRender: function(a, b) {
        MainThread.push(function() {
            Entity.setRenderType(a, b)
        })
    },
    rideAnimal: function(a, b) {
        Entity.rideAnimal(a, b)
    },
    getNameTag: function(a) {
        return Entity.getNameTag(a)
    },
    setNameTag: function(a, b) {
        return Entity.setNameTag(a, b)
    },
    getTarget: function(a) {
        return Entity.getTarget(a)
    },
    setTarget: function(a, b) {
        return Entity.setTarget(a, b)
    },
    setMobile: function(a, b) {
        Entity.setImmobile(a, !b)
    },
    getSneaking: function(a) {
        return Entity.isSneaking(a)
    },
    setSneaking: function(a, b) {
        return Entity.setSneaking(a, b)
    },
    getRider: function(a) {
        return Entity.getRider(a)
    },
    getRiding: function(a) {
        return Entity.getRiding(a)
    },
    setFire: function(a, b) {
        Entity.setFireTicks(a, b || 0)
    },
    health: function(a) {
        return {
            get: function() {
                return this.getHealth(a)
            },
            set: function(b) {
                this.setHealth(a, b)
            },
            getMax: function() {
                return this.getMaxHealth(a)
            },
            setMax: function(b) {
                this.setMaxHealth(a, b)
            }
        }
    },
    getHealth: function(a) {
        return Entity.getHealth(a)
    },
    setHealth: function(a, b) {
        Entity.setHealth(a, b)
    },
    getMaxHealth: function(a) {
        return Entity.getMaxHealth(a)
    },
    setMaxHealth: function(a,
        b) {
        Entity.setMaxHealth(a, b)
    },
    setPosition: function(a, b, c, d) {
        setPosition(a, b, c, d)
    },
    getPosition: function(a) {
        return {
            x: Entity.getX(a),
            y: Entity.getY(a),
            z: Entity.getZ(a)
        }
    },
    addPosition: function(a, b, c, d) {
        var e = this.getPosition(a);
        this.setPosition(a, e.x + b, e.y + c, e.z + d)
    },
    setVelocity: function(a, b, c, d) {
        setVelX(a, b);
        setVelY(a, c);
        setVelZ(a, d)
    },
    getVelocity: function(a) {
        return {
            x: Entity.getVelX(a),
            y: Entity.getVelY(a),
            z: Entity.getVelZ(a)
        }
    },
    addVelocity: function(a, b, c, d) {
        var e = this.getVelocity(a);
        this.setVelocity(a, e.x +
            b, e.y + c, e.z + d)
    },
    getDistanceBetweenCoords: function(a, b) {
        return Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2) + Math.pow(a.z - b.z, 2))
    },
    getDistanceToCoords: function(a, b) {
        return this.getDistanceBetweenCoords(this.getPosition(a), b)
    },
    getDistanceToEntity: function(a, b) {
        return this.getDistanceBetweenCoords(this.getPosition(a), this.getPosition(b))
    },
    getXZPlayerDis: function(a) {
        var b = getPlayerX() - Entity.getX(a);
        a = getPlayerZ() - Entity.getZ(a);
        return Math.sqrt(b * b + a * a)
    },
    getLookAngle: function(a) {
        return {
            pitch: __degreesToRad(-Entity.getPitch(a)),
            yaw: __degreesToRad(Entity.getYaw(a))
        }
    },
    setLookAngle: function(a, b, c) {
        Entity.setRot(a, __radToDegrees(b) || 0, __radToDegrees(-c) || 0)
    },
    getLookVectorByAngle: function(a) {
        return {
            x: -Math.sin(a.yaw) * Math.cos(a.pitch),
            y: Math.sin(a.pitch),
            z: Math.cos(a.yaw) * Math.cos(a.pitch)
        }
    },
    getLookVector: function(a) {
        a = this.getLookAngle(a);
        return this.getLookVectorByAngle(a)
    },
    getLookAt: function(a, b, c, d) {
        a = this.getPosition(a);
        b -= a.x;
        c -= a.y;
        d -= a.z;
        a = Math.sqrt(b * b + c * c + d * d);
        return {
            yaw: Math.atan2(-(b / a), d / a),
            pitch: Math.asin(c / a)
        }
    },
    lookAt: function(a, b, c, d) {
        b = this.getLookAt(a, b, c, d);
        this.setLookAngle(a, b.yaw, b.pitch)
    },
    lookAtCoords: function(a, b) {
        this.lookAt(a, b.x, b.y, b.z)
    },
    moveToTarget: function(a, b, c) {
        var d = this.getPosition(a),
            e = this.getVelocity(a),
            f = b.x - d.x,
            g = b.y - d.y;
        b = b.z - d.z;
        var h = Math.sqrt(f * f + g * g + b * b);
        d = Math.min(h, c.speed || 0);
        f *= d / h;
        g *= d / h;
        b *= d / h;
        c.denyY && (g = e.y, (c = c.jumpVel || 0) && .001 > Math.abs(e.y + .0781) && (.001 > Math.abs(e.x) && Math.abs(f) > .1 * d || .001 > Math.abs(e.z) && Math.abs(b) > .1 * d) && (g = c));
        this.setVelocity(a, f, g, b)
    },
    moveToAngle: function(a,
        b, c) {
        speed = (c.speed || 0) + 1;
        b = this.getLookVectorByAngle(b);
        var d = this.getPosition(a);
        this.moveToTarget(a, {
            x: d.x + b.x * speed,
            y: d.y + b.y * speed,
            z: d.z + b.z * speed
        }, c)
    },
    moveToLook: function(a, b) {
        this.moveToAngle(a, this.getLookAngle(a), b)
    },
    getMovingVector: function(a) {
        a = this.getVelocity(a);
        a.size = Math.sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
        a.xzsize = Math.sqrt(a.x * a.x + a.z * a.z);
        a.x /= a.size;
        a.y /= a.size;
        a.z /= a.size;
        return a
    },
    getMovingAngle: function(a) {
        a = this.getMovingVector(a);
        return {
            pitch: Math.asin(a.y) || 0,
            yaw: Math.atan2(-a.x,
                a.z) || 0
        }
    },
    getMovingAngleByPositions: function(a, b) {},
    findNearest: function(a, b, c) {
        var d = b ? EntityDataRegistry.getDataForType(b) : EntityDataRegistry.getAllData();
        b = null;
        var e = 999999999,
            f;
        for (f in d) d = this.getDistanceToCoords(parseInt(f), a), d < e && (b = parseInt(f), e = d);
        return c && e > c ? null : b
    },
    getAllInRange: function(a, b, c) {
        c = c ? EntityDataRegistry.getDataForType(c) : EntityDataRegistry.getAllData();
        var d = [],
            e;
        for (e in c) this.getDistanceToCoords(parseInt(e), a) < b && d.push(parseInt(e));
        return d
    },
    getInventory: function(a,
        b, c) {
        return new EntityInventory(a, b, c)
    },
    getProjectileItem: function(a) {
        return ProjectileItemRegistry.getItem(a)
    }
};
Callback.addCallback("CoreConfigured", function(a) {
    EntityAPI.fixEntityRotation = a.access("util.force_entity_rotation")
});

function getMcContext() {
    return com.mojang.minecraftpe.MainActivity.currentMainActivity.get()
}
var GuiUtils = {
        colorPaint: new android.graphics.Paint,
        textPaint: new android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG),
        textCenterPaint: new android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG),
        iconPaint: new android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG),
        GetDisplaySize: function() {
            var a = getMcContext();
            if (16 < android.os.Build.VERSION.SDK_INT) {
                var b = a.getWindow().getDecorView().getSystemUiVisibility();
                var c = android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                if (b && 0 != c) return c =
                    new android.util.DisplayMetrics, a.getWindowManager().getDefaultDisplay().getRealMetrics(c), b = c.widthPixels, a = c.heightPixels, [b, a]
            } else Logger.Log("old SDK detected", "GUI");
            b = a.getWindowManager().getDefaultDisplay().getWidth();
            a = a.getWindowManager().getDefaultDisplay().getHeight();
            return [b, a]
        },
        Run: function(a) {
            getMcContext().runOnUiThread(new java.lang.Runnable({
                run: function() {
                    try {
                        a()
                    } catch (b) {
                        print(b), Logger.Log("error in gui thread execution: " + b, "ERROR"), Logger.LogError(b)
                    }
                }
            }))
        },
        GetGuiAssetName: function(a) {
            a =
                new String(a);
            var b = a.split(".");
            return 1 < b.length ? (b.pop(), b.join(".")) : a
        },
        FastScale: function(a, b) {
            return a ? android.graphics.Bitmap.createScaledBitmap(a, a.width * b, a.height * b, !1) : null
        },
        GetFrame: function(a, b, c, d, e) {
            var f = parseInt(a / d);
            d = parseInt(b / d);
            var g = android.graphics.Bitmap.createBitmap(f, d, android.graphics.Bitmap.Config.ARGB_8888),
                h = new android.graphics.Canvas(g),
                k = android.graphics.Bitmap.createBitmap(f, d, android.graphics.Bitmap.Config.ARGB_8888),
                m = new android.graphics.Canvas(k);
            e && (this.colorPaint.setColor(e),
                h.drawRect(1, 1, f - 1, d - 1, this.colorPaint));
            e = GuiWindowProvider.Images[c];
            if (!e) return print("frame prototype bitmap is missing: " + c), null;
            var l = android.graphics.Bitmap.createBitmap(e, 3, 0, 10, 4),
                n = android.graphics.Bitmap.createBitmap(e, 3, 12, 10, 4);
            c = android.graphics.Bitmap.createBitmap(e, 0, 3, 4, 10);
            for (var r = android.graphics.Bitmap.createBitmap(e, 12, 3, 4, 10), p = 0; p < f; p += 10) m.drawBitmap(l, p, 0, null), m.drawBitmap(n, p, d - 4, null);
            for (l = 0; l < d; l += 10) m.drawBitmap(c, 0, l, null), m.drawBitmap(r, f - 4, l, null);
            for (p = 0; 2 > p; p++)
                for (l =
                    0; 2 > l; l++) k.setPixel(p, l, 0), k.setPixel(f - p - 1, l, 0), k.setPixel(p, d - l - 1, 0), k.setPixel(f - p - 1, d - l - 1, 0);
            m.drawBitmap(android.graphics.Bitmap.createBitmap(e, 0, 0, 4, 4), 0, 0, null);
            m.drawBitmap(android.graphics.Bitmap.createBitmap(e, 12, 0, 4, 4), f - 4, 0, null);
            m.drawBitmap(android.graphics.Bitmap.createBitmap(e, 0, 12, 4, 4), 0, d - 4, null);
            m.drawBitmap(android.graphics.Bitmap.createBitmap(e, 12, 12, 4, 4), f - 4, d - 4, null);
            h.drawBitmap(k, 0, 0, null);
            return android.graphics.Bitmap.createScaledBitmap(g, a, b, !1)
        },
        createBitmapByMatrix: function(a,
            b, c) {
            if (a) return a = android.graphics.Bitmap.createScaledBitmap(a, .5 * c, .5 * c, !1), android.graphics.Bitmap.createBitmap(a, 0, 0, a.getWidth(), a.getHeight(), b, !1)
        },
        genBlockTexture: function(a, b, c) {
            var d, e = new android.graphics.Matrix;
            b = android.graphics.Bitmap.createBitmap(c, c, android.graphics.Bitmap.Config.ARGB_8888);
            var f = new android.graphics.Canvas(b),
                g = [];
            for (k in a) {
                var h = a[k][0] + "_" + (a[k][1] || 0) + ".png";
                (d = FileTools.ReadImageAsset(h)) ? g[k] = d: (h = a[k][0], (d = FileTools.ReadImageAsset(h)) ? g[k] = android.graphics.Bitmap.createScaledBitmap(d,
                    c, c, !1) : (Logger.Log("failed to load texture for block icon, it will be replaced with missing icon: " + h + " (" + a[k] + ")", "WARNING"), g[k] = ItemIconSource.getNamedIcon("missing_block")))
            }
            d = new android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG);
            d.setColorFilter(new android.graphics.PorterDuffColorFilter(android.graphics.Color.rgb(125, 125, 125), android.graphics.PorterDuff.Mode.MULTIPLY));
            h = new android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG);
            h.setColorFilter(new android.graphics.PorterDuffColorFilter(android.graphics.Color.rgb(190,
                190, 190), android.graphics.PorterDuff.Mode.MULTIPLY));
            a = c / 32;
            e.reset();
            e.setPolyToPoly([0, 0, 32, 0, 32, 32, 0, 32], 0, [0, 13.5, 25, 0, 51, 13.5, 25, 27], 0, 4);
            var k = this.createBitmapByMatrix(g[1], e, c);
            e.reset();
            e.setPolyToPoly([0, 0, 26, 0, 26, 32, 0, 32], 0, [0, 11, 21.8, 0, 21.8, 32, 0, 43], 0, 4);
            var m = this.createBitmapByMatrix(g[3], e, c);
            e.reset();
            e.setPolyToPoly([0, 0, 25, 0, 25, 32, 0, 32], 0, [0, 0, 20, 11, 20, 43, 0, 32], 0, 4);
            e = this.createBitmapByMatrix(g[4], e, c);
            f.drawBitmap(e, parseInt(3.5 * a), parseInt(7 * a), h);
            f.drawBitmap(m, parseInt(16 * a),
                parseInt(7 * a), d);
            c = android.graphics.Bitmap.createBitmap(c, c, android.graphics.Bitmap.Config.ARGB_8888);
            (new android.graphics.Canvas(c)).drawBitmap(k, parseInt(3.5 * a), parseInt(.4 * a), this.iconPaint);
            f.drawBitmap(c, 0, 0, null);
            return b
        }
    },
    STATIC_CONTAINER_OPENID = 0;

function Container(a) {
    this.slots = {};
    this.openID = -1;
    this.tileEntity = a;
    this.isOpened = function() {
        if (this.currentGuiScreen) return this.currentGuiScreen.slotSource == this && this.currentGuiScreen.isOpened()
    };
    this.currentGuiScreen = null;
    this.openAs = function(a) {
        !this.isOpened() && a && (this.currentGuiScreen = a, a.setSlotSource(this), a.open(), this.openID = ++STATIC_CONTAINER_OPENID)
    };
    this.getGuiScreen = function() {
        if (this.currentGuiScreen && this.isOpened()) return this.currentGuiScreen
    };
    this.getGuiContent = function() {
        var a =
            this.getGuiScreen();
        if (a) return a.content
    };
    this.close = function() {
        this.isOpened() && this.currentGuiScreen.close()
    };
    this.getSlot = function(a) {
        return this.slots[a] || this.createSlot(a)
    };
    this.createSlot = function(a) {
        var b = {
            id: 0,
            count: 0,
            data: 0
        };
        return this.slots[a] = b
    };
    this.setSlot = function(a, c, d, e) {
        a = this.getSlot(a);
        a.id = c;
        a.count = d;
        a.data = e
    };
    this.clearSlot = function(a) {
        this.setSlot(a, 0, 0, 0)
    };
    this.validateSlot = function(a) {
        var b = this.getSlot(a);
        b.id = b.id || 0;
        b.count = b.count || 0;
        b.data = b.data || 0;
        (1 > b.id || 1 > b.count) &&
        this.clearSlot(a);
        return b
    };
    this.validateAll = function() {
        for (var a in this.slots) this.validateSlot(a)
    };
    this.dropAt = function(a, c, d) {
        for (var b in this.slots) this.dropSlot(b, a, c, d)
    };
    this.dropSlot = function(a, c, d, e) {
        var b = this.validateSlot(a);
        0 < b.id && Level.dropItem(c, d, e, 0, b.id, b.count, b.data);
        this.clearSlot(a)
    };
    this.save = function() {
        var a = {},
            c;
        for (c in this.slots) {
            var d = this.slots[c];
            0 < d.id && !c.startsWith("_inv") && (a[c] = d)
        }
        return {
            slots: a
        }
    };
    this.read = function(a) {
        a && (this.slots = a.slots || {})
    };
    this.guiElements = {};
    this.clearElementData = function() {
        this.guiElements = {}
    };
    this.setElementData = function(a, c) {
        this.guiElements[a] = c
    };
    this.getElement = function(a) {
        return this.guiElements[a]
    };
    this.requireElement = function(a, c) {
        var b = this.getElement(a);
        return b && b.type == c ? b : null
    };
    this.setScale = function(a, c) {
        var b = this.requireElement(a, "scale");
        b && (b.value = Math.min(1, Math.max(0, c || 0)))
    };
    this.setScaleTexture = function(a, c) {
        var b = this.requireElement(a, "scale");
        b && b.setBitmap(c)
    };
    this.setScaleAsLiquid = function(a, c, d) {
        if (a = this.requireElement(a,
                "scale"))
            if (a.value = Math.min(1, Math.max(0, d || 0)), a.bitmap && (c = LiquidRegistry.getLiquidUIBitmap(c, a.bitmap.width, a.bitmap.height))) a.bitmap = c
    };
    this.setText = function(a, c) {
        var b = this.getElement(a);
        b && (b.text = c, b._text = null)
    };
    this.getText = function(a) {
        if (a = this.getElement(a)) return a.text
    };
    this.setTextColor = function(a, c) {
        var b = this.getElement(a);
        b && b.font && (b.font.color = c)
    };
    this.setTextSize = function(a, c) {
        var b = this.getElement(a);
        b && b.font && (b.font.size = c)
    };
    this.setTextShadow = function(a, c) {
        var b = this.getElement(a);
        b && b.font && (b.font.shadow = c)
    };
    this.isElementTouched = function(a) {
        if (a = this.getElement(a)) return a.isTouched
    };
    this.getElementTouchPosition = function(a) {
        if (a = this.getElement(a)) return a.touchPosition
    };
    this.applyChanges = function() {};
    this.refreshSlots = function() {}
}
var ItemIconSource = {
        cache: [],
        overrides: {},
        __copyBitmap: function(a) {
            return a.copy(android.graphics.Bitmap.Config.ARGB_8888, !0)
        },
        addOverride: function(a, b) {
            this.overrides[a] = b
        },
        getNamedIcon: function(a) {
            this.overrides[a] && (a = this.overrides[a]);
            if (this.cache[a]) return this.cache[a];
            var b = FileTools.ReadImageAsset(a + ".png");
            b || (b = GuiAPI.requireBitmap(a));
            return this.cache[a] = b
        },
        getItemIcon: function(a, b) {
            var c = "__item_" + parseInt(a) + ":" + parseInt(b);
            if (this.cache[c]) return this.cache[c];
            var d = this.getNamedIcon(a +
                "_" + b);
            d || (d = this.getNamedIcon(a + "")) || (d = this.getNamedIcon("missing_icon"));
            var e = android.graphics.Bitmap.createBitmap(16, 16, android.graphics.Bitmap.Config.ARGB_8888),
                f = ItemRegistry.getMaxDamage(a);
            if (d) {
                d = this.__copyBitmap(d);
                if (0 < f && 0 < b)
                    for (var f = 1 - b / f, g = android.graphics.Color.rgb(255 * (1 - f), 255 * f, 0), h = 0; 16 > h; h++) e.setPixel(h, 14, h + .5 < 16 * f ? g : android.graphics.Color.BLACK);
                (new android.graphics.Canvas(d)).drawBitmap(android.graphics.Bitmap.createScaledBitmap(e, d.getWidth(), d.getHeight(), !1), 0, 0, null)
            }
            return this.cache[c] =
                d
        },
        getScaledItemIcon: function(a, b, c, d) {
            c = parseInt(c);
            d = parseInt(d);
            var e = "__item_" + a + "_" + b + "$" + c + "x" + d;
            if (this.cache[e]) return this.cache[e];
            a = android.graphics.Bitmap.createScaledBitmap(this.getItemIcon(a, b), c, d, !1);
            return this.cache[e] = a
        },
        getImageNameWithOverride: function(a) {
            a += "";
            this.overrides[a] && (a = this.overrides[a]);
            return a + ".png"
        },
        getIconName: function(a, b) {
            var c = this.getNamedIcon(a + "_" + b);
            return c ? this.getImageNameWithOverride(a + "_" + b) : (c = this.getNamedIcon(a + "")) ? this.getImageNameWithOverride(a) :
                "missing_icon.png"
        }
    },
    PlayerInventorySlotSource = {
        source: [],
        updating: !1,
        setUpdating: function(a) {
            this.updating = a
        },
        getSource: function(a) {
            this.source[a] || (this.source[a] = {
                id: 0,
                count: 0,
                data: 0,
                apply: function() {
                    Player.setInventorySlot(a, this.id, this.count, this.data)
                }
            });
            return this.source[a]
        },
        update: function(a) {
            if (a || WorldAPI.isWorldLoaded() && this.updating)
                for (a = 0; 45 > a; a++) {
                    var b = this.getSource(a);
                    b.id = Player.getInventorySlot(a);
                    b.count = Player.getInventorySlotCount(a);
                    b.data = Player.getInventorySlotData(a)
                }
        },
        refresh: function() {
            this.update(!0)
        }
    };
Callback.addCallback("tick", function() {
    PlayerInventorySlotSource.update()
});
var TOUCH_EVENT_DOWN = 0,
    TOUCH_EVENT_DOWN_NOCALL = 1,
    TOUCH_EVENT_UP = 2,
    TOUCH_EVENT_UP_NOCALL = 3,
    TOUCH_EVENT_UPDATE = 4,
    TOUCH_EVENT_UPDATE_NOCALL = 5,
    GuiWindowProvider = {
        windows: [],
        lastOpenID: 1,
        refreshInventorySource: function() {
            var a = !1,
                b;
            for (b in this.windows)
                if (this.windows[b].requireInventory) {
                    a = !0;
                    break
                }
            PlayerInventorySlotSource.setUpdating(a)
        },
        addWindow: function(a) {
            this.removeWindow(a);
            this.windows.push(a)
        },
        removeWindow: function(a) {
            for (var b in this.windows) this.windows[b] == a && this.windows.splice(b--, 1)
        },
        openWindow: function(a) {
            this.addWindow(a);
            this.refreshInventorySource();
            a.isOpened || (a.openID = this.lastOpenID++, a.openUI());
            a.isOpened = !0;
            this.threadRunning || this.StartThread()
        },
        closeWindow: function(a) {
            this.removeWindow(a);
            this.refreshInventorySource();
            a.isOpened && (a.closeUI(), a.openID = -1);
            a.isOpened = !1;
            1 > this.windows.length && this.StopThread()
        },
        threadID: 0,
        backgroundThreadPriority: -5,
        renderThreadPriority: 18,
        threadRunning: !1,
        setThreadPriority: function(a) {
            this.backgroundThreadPriority = parseInt(a) || 0;
            Logger.Log("background ui thread priority set to " + this.backgroundThreadPriority, "CORE")
        },
        setRenderThreadPriority: function(a) {
            this.renderThreadPriority = parseInt(a) || 0;
            var b = this;
            GuiUtils.Run(function() {
                android.os.Process.setThreadPriority(b.renderThreadPriority)
            });
            Logger.Log("render ui thread priority set to " + this.renderThreadPriority, "CORE")
        },
        StartThread: function() {
            this.threadID++;
            var a = this.ThreadFunc(this.threadID);
            this.thread = new java.lang.Thread({
                run: a
            });
            this.thread.start();
            this.threadRunning = !0
        },
        ThreadFunc: function(a) {
            var b = this;
            return function() {
                for (android.os.Process.setThreadPriority(b.backgroundThreadPriority); a == b.threadID;) {
                    try {
                        b.Frame(a)
                    } catch (c) {
                        print(c + "\n" + c.stack)
                    }
                    java.lang.Thread.yield()
                }
                GuiElementSelection.setSelection(null, null);
                b.threadRunning = !1
            }
        },
        Frame: function(a) {
            a = java.lang.System.currentTimeMillis();
            !this.touchEvent.longClickCalled && this.touchEvent.isTouched && 800 < a - this.touchEvent.time && (this.onClick(this.touchEvent.x, this.touchEvent.y, !0, TOUCH_EVENT_UPDATE), this.touchEvent.longClickCalled = !0);
            java.lang.Thread.sleep(40);
            for (var b in this.windows) this.windows[b].drawElements();
            for (; 0 < this.threadStack.size();) java.lang.Thread.yield(), a = this.threadStack.get(0), this.threadStack.remove(0), a && a.func();
            for (a = 0; 24 > a++;) {
                var c = !1;
                for (b in this.windows)
                    if (this.windows[b] && this.windows[b].isDirty()) {
                        c = !0;
                        break
                    }
                if (!c) break;
                java.lang.Thread.sleep(10)
            }
        },
        threadStack: new java.util.ArrayList,
        ExecInThread: function(a) {
            java.lang.Thread.yield();
            this.threadStack.add({
                func: a,
                thread: this.threadID
            })
        },
        StopThread: function() {
            this.threadID++;
            this.threadRunning = !1
        },
        touchEvent: {
            time: 0,
            isTouched: !1,
            x: 0,
            y: 0
        },
        registerTouchEvent: function(a, b) {
            try {
                this.touchEvent.window = a;
                var c = b.getAction();
                if (0 == c) this.touchEvent.x = b.getX(), this.touchEvent.y = b.getY(), this.touchEvent.isTouched = !0, this.touchEvent.time = java.lang.System.currentTimeMillis(), this.touchEvent.longClickCalled = !1, this.onClick(this.touchEvent.x, this.touchEvent.y, !1, TOUCH_EVENT_DOWN_NOCALL);
                else if (1 == c) {
                    this.touchEvent.isTouched = !1;
                    if (this.touchEvent.longClickCalled) this.onClick(this.touchEvent.x,
                        this.touchEvent.y, !1, TOUCH_EVENT_UP_NOCALL);
                    else this.onClick(this.touchEvent.x, this.touchEvent.y, !1, TOUCH_EVENT_UP);
                    this.touchEvent.longClickCalled = !1
                } else if (3 == c) this.touchEvent.isTouched = !1, this.touchEvent.longClickCalled = !0;
                else this.onClick(this.touchEvent.x, this.touchEvent.y, !1, TOUCH_EVENT_UPDATE_NOCALL)
            } catch (d) {
                print(d)
            }
            return !0
        },
        onClick: function(a, b, c, d) {
            for (var e in this.windows) {
                var f = this.windows[e];
                if (this.touchEvent.window == f) f.onClick(a, b, c, d)
            }
        },
        Images: [],
        BitmapCache: {
            cache: {},
            getScaled: function(a,
                b) {
                b || (b = 1);
                var c = a + "/" + b;
                if (this.cache[c]) return this.cache[c];
                var d = GuiWindowProvider.Images[a];
                return d ? (this.cache[c] = android.graphics.Bitmap.createScaledBitmap(d, d.width * b, d.height * b, !1), this.cache[c]) : null
            },
            getSized: function(a, b, c) {
                var d = a + "/" + b + "x" + c;
                return this.cache[d] ? this.cache[d] : (a = GuiWindowProvider.Images[a]) ? (this.cache[d] = android.graphics.Bitmap.createScaledBitmap(a, b, c, !1), this.cache[d]) : null
            },
            getScaledForRaw: function(a, b) {
                if (a) {
                    b || (b = 1);
                    var c = a + "/" + b;
                    this.cache[c] || (this.cache[c] =
                        android.graphics.Bitmap.createScaledBitmap(a, a.width * b, a.height * b, !1));
                    return this.cache[c]
                }
            }
        }
    };
Callback.addCallback("CoreConfigured", function(a) {
    GuiWindowProvider.setThreadPriority(a.access("gui.gui_background_thread_priortiy"));
    GuiWindowProvider.setRenderThreadPriority(a.access("gui.gui_render_thread_priority"))
});

function GuiElementProvider(a) {
    this.drawCommands = [];
    this.guiElements = {};
    this.window = a;
    this.clearBitmap = null;
    this.setClearBitmap = function(a) {
        this.clearBitmap = a;
        this.window && (this.window.clearBitmap = a)
    };
    this.reset = function() {
        this.drawCommands = [];
        this.guiElements = {}
    };
    this.slotSource = null;
    this.setSlotSource = function(a) {
        this.slotSource = a
    };
    this.drawElements = function(a, c) {
        for (var b in this.guiElements) try {
            this.guiElements[b].canDraw && this.guiElements[b].draw(this.window, a, c)
        } catch (e) {}
    };
    this.clickScale =
        1;
    this.setClickScale = function(a) {
        this.clickScale = a
    };
    this.onClick = function(a, c, d, e) {
        a /= this.clickScale;
        c /= this.clickScale;
        var b = this.slotSource,
            g = null;
        b && (g = b.tileEntity);
        var h = e == TOUCH_EVENT_DOWN || e == TOUCH_EVENT_UP || e == TOUCH_EVENT_UPDATE,
            k = !(e == TOUCH_EVENT_UP || e == TOUCH_EVENT_UP_NOCALL),
            m;
        for (m in this.guiElements) {
            var l = this.guiElements[m],
                n = l.rect;
            if (a > n.x && c > n.y && a < n.x + n.width && c < n.y + n.height) {
                position = {
                    x: (a - n.x) / n.width,
                    y: (c - n.y) / n.height
                };
                l.isTouched = k;
                l.touchPosition = {
                    x: a,
                    y: c
                };
                if (l.onTouchEvent) l.onTouchEvent(position,
                    e, b, g, this.window, this.window.canvas, this.window.location.scale);
                if (h)
                    if (d && l.onLongClick) l.onLongClick(position, b, g, this.window, this.window.canvas, this.window.location.scale);
                    else if (!d && l.onClick) l.onClick(position, b, g, this.window, this.window.canvas, this.window.location.scale)
            } else l.isTouched = !1
        }
    };
    this.drawClear = function(a) {
        if (this.window && this.window.canvas) {
            this.window.clearColor(android.graphics.Color.WHITE, android.graphics.PorterDuff.Mode.SRC);
            var b = this.window.location,
                d;
            for (d in this.drawCommands)(0, this.drawCommands[d])(this.window,
                this.window.canvas, b.scale);
            this.setClearBitmap(android.graphics.Bitmap.createScaledBitmap(this.window.bitmap, this.window.bitmap.width, this.window.bitmap.height, !1));
            for (d in this.guiElements)(b = this.guiElements[d]) && b.cleaner && (b.cleaner.recycle(), b.cleaner = this.window.getCleaner(b.rect.x, b.rect.y, b.rect.width, b.rect.height));
            a || this.window.postRefresh()
        }
    };
    this.clearDrawCommands = function() {
        this.drawCommands = []
    };
    this.addDrawCommand = function(a) {
        this.drawCommands.push(a)
    };
    this.getElement = function(a) {
        return this.guiElements[a] ||
            null
    };
    this.setElement = function(a, c, d) {
        this.removeElement(a, d);
        c.elementName = a;
        c.canDraw = !1;
        c.isTouched = !1;
        c.touchPosition = {
            x: 0,
            y: 0
        };
        c.cleaner = this.window.getCleaner(c.rect.x, c.rect.y, c.rect.width, c.rect.height);
        var b = this.window;
        d ? (c.drawStart(b, b.canvas, b.location.scale), c.canDraw = !0) : GuiWindowProvider.ExecInThread(function() {
            c.drawStart(b, b.canvas, b.location.scale);
            c.canDraw = !0
        });
        this.guiElements[a] = c
    };
    this.removeElement = function(a, c) {
        var b = this.getElement(a);
        if (b && b.cleaner) {
            var e = b.cleaner;
            c ?
                e && (e.clean(), e.recycle()) : GuiWindowProvider.ExecInThread(function() {
                    e && (e.clean(), e.recycle())
                })
        }
        b && delete this.guiElements[a]
    };
    this.refreshElement = function(a, c) {
        var b = this.getElement(a);
        b && this.setElement(a, b, c)
    };
    this.refreshAllElements = function(a) {
        for (var b in this.guiElements) this.refreshElement(b, a)
    };
    this.clearRAM = function() {
        this.window && (this.window.bitmap && (this.window.bitmap.recycle(), this.window.bitmap = null), this.window.clearBitmap && (this.window.clearBitmap.recycle(), this.clearBitmap = this.window.clearBitmap =
            null));
        for (var a in this.guiElements) {
            var c = this.guiElements[a];
            c.cleaner && (c.cleaner.recycle(), c.cleaner = null)
        }
    }
}
var GuiLoader = {
    InitAndLoad: function() {
        this.ExtractFile("minecraft.ttf", FileTools.workdir + "minecraft.ttf");
        try {
            this.minecraftTypeface = this.LoadTypeface(FileTools.workdir + "minecraft.ttf"), GuiUtils.textPaint.setTypeface(this.minecraftTypeface), GuiUtils.textCenterPaint.setTypeface(this.minecraftTypeface)
        } catch (a) {
            Logger.Log("Minecraft font cannot be loaded, please restart blocklauncher. Error: " + a, "ERROR")
        }
        GuiUtils.textCenterPaint.setTextAlign(android.graphics.Paint.Align.CENTER);
        this.LoadImageAsset("_default_slot",
            "_default_slot.png");
        this.LoadImageAsset("_default_slot_light", "_default_slot_light.png");
        this.LoadImageAsset("_default_slot_dark", "_default_slot_dark.png");
        this.LoadImageAsset("_default_slot_invis", "_default_slot_empty.png");
        this.LoadImageAsset("default_frame_1", "default_frame_1.png");
        this.LoadImageAsset("default_frame_2", "default_frame_2.png");
        this.LoadImageAsset("default_frame_3", "default_frame_3.png");
        this.LoadImageAsset("default_frame_4", "default_frame_4.png");
        this.LoadImageAsset("default_frame_5",
            "default_frame_5.png");
        this.LoadImageAsset("default_frame_6", "default_frame_6.png");
        this.LoadImageAsset("default_frame_7", "default_frame_7.png");
        this.LoadImageAsset("default_frame_8", "default_frame_8.png");
        this.LoadImageAsset("_standart_header_shadow", "_standart_header_shadow.png");
        this.LoadImageAsset("_selection", "_selection.png");
        this.LoadImageAsset("close_button_up", "close_button_up.png");
        this.LoadImageAsset("close_button_down", "close_button_down.png");
        this.LoadImageAsset("_workbench_bar", "_workbench_bar.png");
        this.LoadImageAsset("button_blank_48x24", "_button_blank_48x24.png");
        this.LoadImageAsset("button_prev_48x24", "_button_prev_48x24.png");
        this.LoadImageAsset("button_prev_48x24p", "_button_prev_48x24p.png");
        this.LoadImageAsset("button_next_48x24", "_button_next_48x24.png");
        this.LoadImageAsset("button_next_48x24p", "_button_next_48x24p.png");
        this.LoadImageAsset("_craft_button_up", "_craft_button_up.png");
        this.LoadImageAsset("_craft_button_down", "_craft_button_down.png");
        this.LoadImageAsset("standart_water_ui_texture",
            "_liquid_water_texture_0.png");
        this.LoadImageAsset("standart_lava_ui_texture", "_liquid_lava_texture_0.png");
        this.LoadImageAsset("standart_milk_ui_texture", "_liquid_milk_texture_0.png");
        this.LoadImageAsset("liquid_bar_sample", "_liquid_empty_texture_0.png")
    },
    placeholdMissing: function() {
        GuiAPI.checkAndPlacehold("_default_slot", 16, 16);
        GuiAPI.checkAndPlacehold("_default_slot_light", 16, 16);
        GuiAPI.checkAndPlacehold("_default_slot_dark", 16, 16);
        GuiAPI.checkAndPlacehold("_default_slot_invis", 16, 16);
        GuiAPI.checkAndPlacehold("default_frame_1",
            16, 16);
        GuiAPI.checkAndPlacehold("default_frame_2", 16, 16);
        GuiAPI.checkAndPlacehold("default_frame_3", 16, 16);
        GuiAPI.checkAndPlacehold("default_frame_4", 16, 16);
        GuiAPI.checkAndPlacehold("default_frame_5", 16, 16);
        GuiAPI.checkAndPlacehold("default_frame_6", 16, 16);
        GuiAPI.checkAndPlacehold("default_frame_7", 16, 16);
        GuiAPI.checkAndPlacehold("default_frame_8", 16, 16);
        GuiAPI.checkAndPlacehold("_standart_header_shadow", 500, 10);
        GuiAPI.checkAndPlacehold("_selection", 60, 60);
        GuiAPI.checkAndPlacehold("close_button_up",
            18, 18);
        GuiAPI.checkAndPlacehold("close_button_down", 18, 18);
        GuiAPI.checkAndPlacehold("_workbench_bar", 64, 64);
        GuiAPI.checkAndPlacehold("standart_water_ui_texture", 16, 80);
        GuiAPI.checkAndPlacehold("standart_lava_ui_texture", 16, 80);
        GuiAPI.checkAndPlacehold("standart_milk_ui_texture", 16, 80);
        GuiAPI.checkAndPlacehold("liquid_bar_sample", 16, 80);
        GuiAPI.checkAndPlacehold("button_blank_48x24", 48, 24);
        GuiAPI.checkAndPlacehold("button_prev_48x24", 48, 24);
        GuiAPI.checkAndPlacehold("button_prev_48x24p", 48, 24);
        GuiAPI.checkAndPlacehold("button_next_48x24",
            48, 24);
        GuiAPI.checkAndPlacehold("button_next_48x24p", 48, 24);
        GuiAPI.checkAndPlacehold("_craft_button_up", 48, 20);
        GuiAPI.checkAndPlacehold("_craft_button_down", 48, 20)
    },
    LoadImageAsset: function(a, b) {
        GuiWindowProvider.Images[a] = FileTools.ReadImageAsset(b)
    },
    LoadImageAndCache: function(a) {
        var b = "_cached_" + a;
        if (GuiWindowProvider.Images[b]) return GuiWindowProvider.Images[b];
        a = FileTools.ReadImageAsset(a);
        return GuiWindowProvider.Images[b] = a
    },
    ExtractFile: function(a, b) {
        try {
            b = FileTools.getFullPath(b);
            var c = new java.io.BufferedOutputStream(new java.io.FileOutputStream(b));
            c.write(ModPE.getBytesFromTexturePack(a));
            c.flush();
            c.close()
        } catch (d) {
            Logger.Log("unable to extract asset " + a + " to " + b + ":", "ERROR"), Logger.LogError(d)
        }
    },
    LoadTypeface: function(a) {
        a = FileTools.getFullPath(a);
        return android.graphics.Typeface.createFromFile(a)
    }
};
GuiLoader.InitAndLoad();
Callback.addCallback("PostLoaded", function() {
    GuiLoader.InitAndLoad();
    GuiLoader.placeholdMissing()
});
var GuiElementSelection = {
    setSelection: function(a, b) {
        this.selection = a;
        this.element = b
    },
    getSelection: function() {
        return this.selection
    },
    getSelectedElement: function() {
        return this.element
    }
};

function Window() {
    this.location = {
        x: 0,
        y: 0,
        width: 0,
        height: 0,
        winWidth: 0,
        winHeight: 0,
        scale: 0
    };
    this.canvas = this.popupWindow = null;
    this.elementProvider = new GuiElementProvider(this);
    this.contentProvider = null;
    this.setContentProvider = function(a) {
        this.contentProvider = a
    };
    this.requireInventory = !1;
    this.setRequireInventory = function(a) {
        this.requireInventory = a
    };
    this.isTouchable = !0;
    this.setTouchable = function(a) {
        this.isTouchable = a
    };
    this.isVisual = !1;
    this.setVisual = function(a) {
        this.isVisual = a;
        this.popupWindow && this.popupWindow.setTouchable(!this.isVisual)
    };
    this.isOpened = !1;
    this.openID = -1;
    this.bitmap = this.clearBitmap = null;
    this.open = function() {
        this.postRedraw();
        this.windowInitialized = !1;
        GuiWindowProvider.openWindow(this)
    };
    this.close = function() {
        this.windowInitialized = !1;
        GuiWindowProvider.closeWindow(this)
    };
    this.setLocation = function(a, b, c, d, e) {
        var f = GuiUtils.GetDisplaySize()[0] / 1E3;
        c *= f;
        d *= f;
        e = Math.max(d, e * f || d);
        this.location = {
            x: a * f,
            y: b * f,
            width: c,
            height: e,
            winWidth: c,
            winHeight: d,
            scale: c / 1E3
        }
    };
    this.openUI = function() {
        var a = this,
            b = getMcContext(),
            c = this.location.width,
            d = this.location.height,
            e = c,
            f = d;
        coreEngineConfig.access("gui.faster_render") && (e /= 2, f /= 2);
        this.location.scale = e / 1E3;
        this.elementProvider.setClickScale(c / e);
        this.bitmap && this.bitmap.recycle();
        this.clearBitmap && this.clearBitmap.recycle();
        this.bitmap = android.graphics.Bitmap.createBitmap(e, f, android.graphics.Bitmap.Config.ARGB_8888);
        this.canvas = new android.graphics.Canvas(this.bitmap);
        var g = new android.widget.ImageView(b),
            e = new android.widget.ScrollView(b);
        this.postRedraw();
        this.postRefresh();
        this.popupWindowShowed = !1;
        if (a.location.height <= a.location.winHeight + 5) var h = new android.widget.PopupWindow(g, a.location.winWidth, a.location.winHeight);
        else h = new android.widget.PopupWindow(e, a.location.winWidth, a.location.winHeight), e.addView(g, new android.view.ViewGroup.LayoutParams(-1, -1));
        a.popupWindow = h;
        GuiUtils.Run(function() {
            g.setMinimumWidth(c);
            g.setMinimumHeight(d);
            g.setBackgroundDrawable(new android.graphics.drawable.BitmapDrawable(a.bitmap));
            g.setOnTouchListener({
                onTouch: function(b, c) {
                    return GuiWindowProvider.registerTouchEvent(a,
                        c)
                }
            });
            b.getWindow().getDecorView();
            h.setTouchable(!a.isVisual);
            h.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT));
            a.windowInitialized = !0;
            a.popupWindow = h
        });
        this.popupWindow = h;
        this.bitmapView = g;
        this.initialDraw()
    };
    this.openUIFinal = function() {
        if (!this.popupWindowShowed) {
            this.popupWindowShowed = !0;
            var a = getMcContext().getWindow().getDecorView();
            this.popupWindow.showAtLocation(a, android.view.Gravity.TOP | android.view.Gravity.LEFT, this.location.x, this.location.y)
        }
    };
    this.closeUI = function() {
        var a = this,
            b = this.popupWindow;
        this.bitmapView = this.popupWindow = null;
        this.elementProvider.clearRAM();
        GuiUtils.Run(function() {
            b && b.dismiss();
            a.elementProvider.reset()
        })
    };
    this.onClick = function(a, b, c, d) {
        this.isTouchable && (a /= this.location.scale, b /= this.location.scale, this.elementProvider.onClick(a, b, c, d))
    };
    this.initialDraw = function() {
        this.elementProvider.reset();
        this.contentProvider.postRefresh();
        this.contentProvider.frame(this);
        this.elementProvider.drawClear(this.canvas, this.location.scale, !0);
        this.needRedraw = !1;
        this.elementProvider.refreshAllElements(!0);
        this.needRefresh = !1;
        this.elementProvider.drawElements(this.canvas, this.location.scale)
    };
    this.drawElements = function(a) {
        if (this.windowInitialized || a) {
            this.needRedraw && (this.elementProvider.drawClear(this.canvas, this.location.scale), this.needRedraw = !1);
            this.needRefresh && (this.elementProvider.refreshAllElements(), this.needRefresh = !1);
            this.contentProvider && this.contentProvider.frame(this);
            this.elementProvider.drawElements(this.canvas, this.location.scale);
            var b = this;
            this.isFlushing = !0;
            GuiUtils.Run(function() {
                b.bitmapView && (b.bitmapView.setBackgroundDrawable(new android.graphics.drawable.BitmapDrawable(b.bitmap)), b.isFlushing = !1)
            })
        }
    };
    this.isDirty = function() {
        if (this.isFlushing) return !0;
        if (this.bitmapView) return this.bitmapView.isDirty()
    };
    this.postRedraw = function() {
        this.needRedraw = !0
    };
    this.postRefresh = function() {
        this.needRefresh = !0
    };
    this.clearColor = function(a, b) {
        this.canvas && (b ? this.canvas.drawColor(a, b) : this.canvas.drawColor(a))
    };
    this.getCleaner = function(a,
        b, c, d) {
        var e = new android.graphics.Paint;
        e.setXfermode(android.graphics.PorterDuffXfermode(android.graphics.PorterDuff.Mode.SRC));
        var f = this.clearBitmap && !this.clearBitmap.isRecycled() ? this.clearBitmap : this.bitmap;
        return f && !f.isRecycled() && this.canvas && (a *= this.location.scale, b *= this.location.scale, c *= this.location.scale, d *= this.location.scale, 0 > a && (c = Math.min(c + a, a), a = 0), 0 > b && (d = Math.min(d + b, b), b = 0), c = Math.min(f.width - a - 1, c), d = Math.min(f.height - b - 1, d), 1 <= c && 1 <= d) ? {
            bitmap: android.graphics.Bitmap.createBitmap(f,
                parseInt(a), parseInt(b), c, d),
            canvas: this.canvas,
            clean: function() {
                this.bitmap && !this.bitmap.isRecycled() && this.canvas.drawBitmap(this.bitmap, parseInt(a), parseInt(b), e)
            },
            recycle: function() {
                this.bitmap.recycle()
            },
            refresh: function() {
                c = Math.min(f.width - a - 1, c);
                d = Math.min(f.height - b - 1, d);
                1 <= c && 1 <= d && (this.bitmap = android.graphics.Bitmap.createBitmap(f, a, b, c, d))
            }
        } : {
            clean: function() {},
            recycle: function() {},
            refresh: function() {}
        }
    };
    this.clearArea = function(a, b, c, d) {
        if (a = this.getCleaner(a, b, c, d)) a.clean(), a.recycle()
    };
    this.clearRect = function(a) {
        this.clearArea(a.x, a.y, a.width, a.height)
    };
    this.drawBitmap = function(a, b, c, d) {
        d || (d = 1);
        (a = GuiWindowProvider.BitmapCache.getScaled(a, d * this.location.scale)) && this.canvas.drawBitmap(a, b * this.location.scale, c * this.location.scale, null)
    };
    this.drawRawBitmap = function(a, b, c, d) {
        d || (d = 1);
        (a = GuiWindowProvider.BitmapCache.getScaledForRaw(a, b, c, d * this.location.scale)) && this.canvas.drawBitmap(a, b * this.location.scale, c * this.location.scale, null)
    };
    this.drawFrame = function(a, b, c, d, e, f, g) {
        f ||
            (f = 1);
        a *= this.location.scale;
        b *= this.location.scale;
        c *= this.location.scale;
        d *= this.location.scale;
        c = Math.min(c, this.bitmap.width - a);
        d = Math.min(d, this.bitmap.height - b);
        c = GuiUtils.GetFrame(c, d, e, f * this.location.scale, g);
        this.canvas.drawBitmap(c, a, b, null)
    };
    this.drawText = function(a, b, c, d, e, f, g) {
        c = new String(c);
        d = d || 20;
        g = g ? GuiUtils.textCenterPaint : GuiUtils.textPaint;
        g.setTextSize(d * this.location.scale);
        f && 0 < f && (g.setColor(android.graphics.Color.argb(parseInt(255 * f), 0, 0, 0)), this.canvas.drawText(c, (a + f *
            d * .25) * this.location.scale, (b + f * d * .25) * this.location.scale, g));
        g.setColor(e || android.graphics.Color.BLACK);
        this.canvas.drawText(c, a * this.location.scale, b * this.location.scale, g)
    }
}

function addItemToInventoryAndDropOverload(a, b, c) {
    PlayerAPI.addItemToInventory(a, b, c)
}

function WindowContent(a) {
    this.toJSON = function() {
        return null
    };
    this.fromObject = function(a) {
        this.content = a || {};
        this.content.params || (this.content.params = {});
        this.content.drawing || (this.content.drawing = []);
        this.content.elements || (this.content.elements = {});
        this.content.location && (a = this.content.location, a.fullscreen ? this.setFullscreen() : this.setLocation(a.x, a.y, a.width, a.height, a.scrollHeight))
    };
    this.getContent = function() {
        return this.content
    };
    this.getElements = function() {
        return this.content.elements
    };
    this.getParams = function() {
        return this.content.params
    };
    this.setContent = function(a) {
        this.fromObject(a)
    };
    this.window = new Window;
    this.window.setContentProvider(this);
    var b = GuiUtils.GetDisplaySize(),
        c = b[1] / b[0] * 1E3;
    this.slotSource = null;
    this.setSlotSource = function(a) {
        this.slotSource = a;
        this.window.elementProvider.setSlotSource(a);
        this.postRefresh()
    };
    this.windowGroup = null;
    this.setWindowGroup = function(a) {
        this.windowGroup = a
    };
    this.setRequireInventory = function(a) {
        this.window.setRequireInventory(a)
    };
    this.setTouchable =
        function(a) {
            this.window.setTouchable(a)
        };
    this.setVisual = function(a) {
        this.window.setVisual(a)
    };
    this.setLocation = function(a, b, c, d, e) {
        this.window.setLocation(a, b, c, d, e)
    };
    this.setFullscreen = function() {
        this.setLocation(0, 0, 1E3, c)
    };
    this.open = function() {
        this.openPrepare();
        var a = this;
        GuiUtils.Run(function() {
            a.openFinal()
        })
    };
    this.openPrepare = function() {
        this.applyParams();
        this.refreshDrawing();
        this.postRefresh();
        this.window.open()
    };
    this.openFinal = function() {
        this.window.openUIFinal()
    };
    this.openAt = function(a,
        b, c, d, e) {
        this.setLocation(a, b, c, d, e);
        this.open()
    };
    this.openFullscreen = function() {
        this.setFullscreen();
        this.open()
    };
    this.close = function() {
        this.window.close()
    };
    this.isOpened = function() {
        return this.window.isOpened
    };
    this.postRefresh = function() {
        this.postDrawingRefresh();
        this.postElementRefresh()
    };
    this.postElementRefresh = function() {
        this.__age = 0;
        for (var a in this.content.elements) {
            var b = this.content.elements[a];
            b && (b.__json = "posted refresh")
        }
    };
    this.postDrawingRefresh = function() {
        this.__age = 0;
        this.drawingCommandCache =
            "posted refresh"
    };
    this.getWidth = function() {
        return 1E3
    };
    this.getHeight = function() {
        return this.window.location.height / this.window.location.width * 1E3
    };
    this.fromObject(a);
    var d = this;
    this.windowParams = {
        slotTexture: "_default_slot_light",
        invSlotTexture: "_default_slot",
        frameTexture: "default_frame_8",
        selectionTexture: "_selection",
        closeButtonTexture: "close_button_up",
        closeButtonTexture2: "close_button_down"
    };
    this.applyParams = function() {
        this.setContent(this.content);
        if (this.content.params && this.content.params.textures) {
            var a =
                this.content.params.textures;
            a.slot && (this.windowParams.slotTexture = a.slot);
            a.invSlot && (this.windowParams.invSlotTexture = a.invSlot);
            a.frame && (this.windowParams.frameTexture = a.frame);
            a.selection && (this.windowParams.selectionTexture = a.selection);
            a.closeButton && (this.windowParams.closeButtonTexture = a.closeButton);
            a.closeButton2 && (this.windowParams.closeButtonTexture2 = a.closeButton2)
        }
    };
    var e = {
        background: function(a) {
            return function(b, c, d) {
                b.clearColor(a.color, a.colorMode || android.graphics.PorterDuff.Mode.SRC)
            }
        },
        bitmap: function(a) {
            return function(b, c, d) {
                b.drawBitmap(a.bitmap, a.x, a.y, a.scale)
            }
        },
        frame: function(a) {
            return function(b, c, e) {
                b.drawFrame(a.x, a.y, a.width, a.height, a.bitmap || d.windowParams.frameTexture, a.scale || 1, a.bg || 0)
            }
        },
        text: function(a) {
            return function(b, c, d) {
                c = a.font || {
                    size: a.size,
                    color: a.color,
                    shadow: a.shadow,
                    alignCenter: a.alignCenter
                };
                b.drawText(a.x, a.y, a.text, c.size, c.color, c.shadow, c.alignCenter)
            }
        },
        line: function(a) {
            return function(b, c, d) {
                b = new android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG);
                b.setColor(a.color || android.graphics.Color.BLACK);
                b.setStrokeWidth((a.width || 1) * d);
                c.drawLine(a.x1 * d || 0, a.y1 * d || 0, a.x2 * d || 0, a.y2 * d || 0, b)
            }
        },
        custom: function(a) {
            return function(b, c, d) {
                a.func && a.func(b, c, d)
            }
        }
    };
    this.refreshDrawing = function(a) {
        var b = JSON.stringify(this.content.drawing);
        if (this.drawingCommandCache != b || a) {
            this.drawingCommandCache = b;
            this.window.elementProvider.clearDrawCommands();
            for (var c in this.content.drawing)
                if (a = e[this.content.drawing[c].type]) a = a(this.content.drawing[c]), this.window.elementProvider.addDrawCommand(a);
            this.window.postRedraw()
        }
    };
    var f = {
        slot: function(a, b) {
            var c = b.size || 60,
                e = GuiWindowProvider.Images[b.bitmap];
            e || (b.bitmap = d.windowParams.slotTexture, e = GuiWindowProvider.Images[b.bitmap]);
            var h = c / e.width,
                f = b.bitmap,
                g = d.windowParams.selectionTexture,
                p = c / GuiWindowProvider.Images[g].width,
                e = function(a, b, c) {
                    GuiElementSelection.getSelection();
                    GuiElementSelection.getSelectedElement() != this ? GuiElementSelection.setSelection(this.elementName, this) : (a = this.source) && 0 < a.count ? (addItemToInventoryAndDropOverload(a.id,
                        1, a.data), 1 > --a.count && (a.id = a.count = a.data = 0)) : a.id = a.count = a.data = 0
                },
                q = function(a, b, c) {
                    GuiElementSelection.getSelection();
                    GuiElementSelection.getSelectedElement() != this ? GuiElementSelection.setSelection(this.elementName, this) : ((a = this.source) && 0 < a.count && addItemToInventoryAndDropOverload(a.id, a.count, a.data), a.id = a.count = a.data = 0)
                };
            b.visual && (e = function() {}, q = function() {});
            b.clicker && (b.clicker.onClick && (e = b.clicker.onClick), b.clicker.onLongClick && (q = b.clicker.onLongClick));
            var t = b.source;
            !b.source &&
                d.slotSource && (t = d.slotSource.getSlot(a));
            return {
                rect: {
                    x: b.x,
                    y: b.y,
                    width: c,
                    height: c
                },
                source: t,
                cacheKey: null,
                drawStart: function(a, b, c) {
                    this.cacheKey = null;
                    this.drawSlot(a, b, c);
                    this.cacheKey = null
                },
                drawCallCounter: 0,
                draw: function(a, b, c) {
                    0 == ++this.drawCallCounter % 100 && (this.cacheKey = null);
                    this.drawSlot(a, b, c)
                },
                drawSlot: function(a, c, d) {
                    var e = GuiElementSelection.getSelectedElement() == this;
                    if (this.source) {
                        var k = this.source.id + "." + this.source.count + "." + this.source.data + "." + this.source.guiText + "." + e;
                        if (k !=
                            this.cacheKey || b.drawEveryTick) {
                            b.isTransparent && this.cleaner.clean();
                            a.drawBitmap(f, this.rect.x, this.rect.y, h);
                            var l = 16 * Math.floor(Math.floor(this.rect.width * d * .82) / 16),
                                n = .5 * (this.rect.width * d - l);
                            this.icon = ItemIconSource.getScaledItemIcon(this.source.id, this.source.data, l, l);
                            b.needClean && this.cleaner && this.cleaner.clean();
                            c.drawBitmap(this.icon, this.rect.x * d + n, this.rect.y * d + n, null);
                            if (1 < this.source.count || this.source.guiText || b.showAnyCount && 0 < this.source.id) c = (this.source.guiText || this.source.count) +
                                "", 1 >= c.length ? a.drawText(this.rect.x + .7 * this.rect.width, this.rect.y + .83 * this.rect.height, c, .25 * this.rect.width, android.graphics.Color.WHITE, .45) : 2 >= c.length ? a.drawText(this.rect.x + .5 * this.rect.width, this.rect.y + .83 * this.rect.height, c, .25 * this.rect.width, android.graphics.Color.WHITE, .45) : a.drawText(this.rect.x + .3 * this.rect.width, this.rect.y + .83 * this.rect.height, c, .25 * this.rect.width, android.graphics.Color.WHITE, .45);
                            e && a.drawBitmap(g, this.rect.x, this.rect.y, p);
                            this.cacheKey = k
                        }
                    }
                },
                onClick: e,
                onLongClick: q
            }
        },
        invSlot: function(a, b) {
            b.clicker = {
                onClick: function() {
                    this.transport(1)
                },
                onLongClick: function() {
                    this.transport(64)
                }
            };
            b.bitmap || (b.bitmap = d.windowParams.invSlotTexture);
            var c = this.slot(a, b);
            c.source = PlayerInventorySlotSource.getSource(b.index);
            c.transport = function(a) {
                var b = GuiElementSelection.getSelectedElement();
                if (b) {
                    var c = this.source,
                        b = b.source;
                    if (c && b && (0 == b.id || b.id == c.id && b.data == c.data)) {
                        a = Math.min(Math.min(c.count, a), ItemRegistry.getMaxStack(c.id) - b.count);
                        c.count -= a;
                        b.id = c.id;
                        b.data = c.data;
                        b.count += a;
                        if (1 > c.count || !c.count) c.id = c.count = c.data = 0;
                        this.source.apply()
                    }
                }
            };
            return c
        },
        button: function(a, b) {
            var c = GuiWindowProvider.Images[b.bitmap],
                d = 1,
                e = 1;
            b.scale || (b.scale = 1);
            c && (d = c.width * b.scale, e = c.height * b.scale);
            b.bitmap2 || (b.bitmap2 = b.bitmap);
            b.clicker || (b.clicker = {});
            b.clicker.onClick || (b.clicker.onClick = function() {});
            b.clicker.onLongClick || (b.clicker.onLongClick = b.clicker.onClick);
            b.isTextButton && !b.textOffset && (b.textOffset = {
                x: 0,
                y: 0
            });
            return {
                rect: {
                    x: b.x,
                    y: b.y,
                    width: d,
                    height: e
                },
                text: b.text,
                font: b.font || {},
                timer: -1,
                drawStart: function(a, c, d) {
                    a.drawBitmap(b.bitmap, this.rect.x, this.rect.y, b.scale)
                },
                draw: function(a, c, d) {
                    if (b.drawEveryTick || this._text != this.text || this.wasTouched != this.isTouched) this.isTouched ? a.drawBitmap(b.bitmap2, this.rect.x, this.rect.y, b.scale) : a.drawBitmap(b.bitmap, this.rect.x, this.rect.y, b.scale), this.updateText(a, c, d);
                    this.isTouched && this.updateText(a, c, d);
                    this.wasTouched = this.isTouched
                },
                updateText: function(a, c, d) {
                    a && b.isTextButton && (this._text = this.text, this.font.size =
                        this.font.size || 20, this.font.shadow = this.font.shadow || 0, a.drawText(this.rect.x + b.textOffset.x, this.rect.y + b.textOffset.y, this.text + "", this.font.size, this.font.color || android.graphics.Color.BLACK, this.font.shadow, this.font.alignCenter))
                },
                onClick: function(a, b, c, d, e, f) {
                    this.updateText(d, e, f);
                    this.onClick_(b, c, a, d, e, f)
                },
                onLongClick: function(a, b, c, d, e, f) {
                    this.updateText(d, e, f);
                    this.onLongClick_(b, c, a, d, e, f)
                },
                onTouchEvent: function(a, c, d, e, f, h, g) {
                    if (c == TOUCH_EVENT_DOWN || c == TOUCH_EVENT_DOWN_NOCALL) f.drawBitmap(b.bitmap2,
                        this.rect.x, this.rect.y, b.scale), b.sound && WorldAPI.playSoundAtEntity(getPlayerEnt(), b.sound, 100)
                },
                onClick_: b.clicker.onClick,
                onLongClick_: b.clicker.onLongClick
            }
        },
        closeButton: function(a, b) {
            b.bitmap || (b.bitmap = d.windowParams.closeButtonTexture, b.bitmap2 = d.windowParams.closeButtonTexture2);
            b.clicker = {
                onClick: function() {
                    d.close();
                    b.global && d.windowGroup && d.windowGroup.close()
                }
            };
            return this.button(a, b)
        },
        scale: function(a, b) {
            b.scale || (b.scale = 1);
            b.overlayOffset || (b.overlayOffset = {
                x: 0,
                y: 0
            });
            b.overlayScale ||
                (b.overlayScale = b.scale);
            var c = GuiWindowProvider.BitmapCache.getScaled(b.bitmap, b.scale),
                d = 1,
                e = 1;
            c && (d = c.width, e = c.height);
            return {
                __cachedBitmapName: b.bitmap,
                origins: {
                    width: d / b.scale,
                    height: e / b.scale
                },
                rect: {
                    x: b.x,
                    y: b.y,
                    width: d,
                    height: e
                },
                bitmap: null,
                value: b.value || 0,
                direction: b.direction || 0,
                drawStart: function(a, c, d) {
                    this.bitmap = GuiWindowProvider.BitmapCache.getScaled(b.bitmap, b.scale * d)
                },
                draw: function(a, c, d) {
                    this.value = Math.min(Math.max(this.value || 0, 0), 1);
                    var e = 0,
                        f = 1,
                        h = 0,
                        g = 1;
                    0 == this.direction && (f =
                        this.value);
                    1 == this.direction && (h = 1 - this.value);
                    2 == this.direction && (e = 1 - this.value);
                    3 == this.direction && (g = this.value);
                    var k = 0,
                        l = 0;
                    b.invert && (k = 0 < e ? -e : 1 - f, l = 0 < h ? -h : 1 - g);
                    this.cleaner.clean();
                    if (this.bitmap && 0 < parseInt((f - e) * this.bitmap.width) && 0 < parseInt((g - h) * this.bitmap.height)) try {
                        var m = android.graphics.Bitmap.createBitmap(this.bitmap, (e + k) * this.bitmap.width, (h + l) * this.bitmap.height, (f - e) * this.bitmap.width, (g - h) * this.bitmap.height);
                        c.drawBitmap(m, this.rect.x * d + this.bitmap.width * e, this.rect.y * d + this.bitmap.height *
                            h, null)
                    } catch (u) {}
                    b.overlay && a.drawBitmap(b.overlay, this.rect.x + b.overlayOffset.x, this.rect.y + b.overlayOffset.y, b.overlayScale)
                },
                setBitmap: function(a, c) {
                    if (this.__cachedBitmapName == a && !c) return !1;
                    this.__cachedBitmapName = a;
                    var d = GuiWindowProvider.BitmapCache.getScaled(a, b.scale);
                    if (!d) return !1;
                    this.rect.width = d.width;
                    this.rect.height = d.height;
                    this.origins.width = d.width / b.scale;
                    this.origins.height = d.height / b.scale;
                    this.bitmap = d;
                    return !0
                }
            }
        },
        text: function(a, b) {
            return {
                rect: {
                    x: b.x,
                    y: b.y,
                    width: b.width ||
                        1,
                    height: b.height || 1
                },
                text: b.text,
                font: b.font || {},
                drawText: function(a, b, c) {
                    this.font.size = this.font.size || 20;
                    this.font.shadow = this.font.shadow || 0;
                    a.drawText(this.rect.x, this.rect.y + .66 * this.rect.height - this.font.size * this.font.shadow * .25 * c, this.text, this.font.size, this.font.color || android.graphics.Color.BLACK, this.font.shadow, this.font.alignCenter)
                },
                drawStart: function(a, c, d) {
                    b.isStatic && this.drawText(a, c, d)
                },
                draw: function(a, c, d) {
                    b.isStatic || (this.cleaner.clean(), this.drawText(a, c, d))
                }
            }
        },
        image: function(a,
            b) {
            b.scale || (b.scale = 1);
            b.overlayOffset || (b.overlayOffset = {
                x: 0,
                y: 0
            });
            b.overlayScale || (b.overlayScale = b.scale);
            b.clicker || (b.clicker = {});
            var c = GuiWindowProvider.BitmapCache.getScaled(b.bitmap, b.scale),
                d = 1,
                e = 1;
            c && (d = c.width + 1, e = c.height + 1);
            return {
                rect: {
                    x: b.x,
                    y: b.y,
                    width: d,
                    height: e
                },
                drawStart: function(a, c, d) {
                    a.drawBitmap(b.bitmap, this.rect.x, this.rect.y, b.scale);
                    b.overlay && a.drawBitmap(b.overlay, this.rect.x + b.overlayOffset.x, this.rect.y + b.overlayOffset.y, b.overlayScale)
                },
                draw: function() {},
                onClick: b.clicker.onClick,
                onLongClick: b.clicker.onLongClick
            }
        },
        textField: function(a, b) {
            b.scale || (b.scale = 1);
            b.clicker || (b.clicker = {});
            var c = GuiWindowProvider.BitmapCache.getScaled(b.bitmap, b.scale),
                d = 1,
                e = 1;
            c && (d = c.width + 1, e = c.height + 1);
            b.padding || (b.padding = {
                x: e / 7,
                y: e / 7
            });
            b.maxLen || (b.maxLen = parseInt((d - 2 * b.padding.x) / ((b.font ? b.font.size : 20) || 20) * 20 / 14));
            return {
                rect: {
                    x: b.x,
                    y: b.y,
                    width: d,
                    height: e
                },
                _text: null,
                text: b.text,
                font: b.font || {},
                drawStart: function(a, c, d) {
                    a.drawBitmap(b.bitmap, this.rect.x, this.rect.y, b.scale)
                },
                draw: function(a,
                    c, d) {
                    this._text != this.text && (a.drawBitmap(b.bitmap, this.rect.x, this.rect.y, b.scale), this.updateText(a, c, d));
                    this.field && (this.text = this.field.getText() + "")
                },
                updateText: function(a, c, d) {
                    a && (this._text = this.text, this.font.size = this.font.size || 20, this.font.shadow = this.font.shadow || 0, c = this.text + "", b.maxLen && c.length > b.maxLen && (c = "..." + c.substr(c.length - b.maxLen + 1, c.length)), a.drawText(this.rect.x + b.padding.x, this.rect.y + .9 * this.rect.height - this.font.size * this.font.shadow * .25 * d - b.padding.y, c, this.font.size,
                        this.font.color || android.graphics.Color.BLACK, this.font.shadow, this.font.alignCenter))
                },
                onClick: function() {
                    var a = this;
                    GuiUtils.Run(function() {
                        var c = getMcContext();
                        a.field = new android.widget.EditText(c);
                        a.field.setText(a.text);
                        c = android.app.AlertDialog.Builder(c);
                        c.setTitle(b.title || "Input Text:");
                        c.setView(a.field);
                        c.setNeutralButton("accept", {
                            onClick: function() {
                                a.field = null;
                                return !1
                            }
                        });
                        c.show()
                    })
                }
            }
        }
    };
    this.refreshElements = function() {
        for (var a in this.content.elements) {
            var b = this.content.elements[a];
            if (b) {
                var c = b.__json;
                b.__json = null;
                var d = JSON.stringify(b);
                c != d && (c = this.convertElement(a, b), this.window.elementProvider.setElement(a, c), this.slotSource && this.slotSource.setElementData(a, c), d = JSON.stringify(b));
                b.__json = d
            } else this.window.elementProvider.removeElement(a)
        }
    };
    this.convertElement = function(a, b) {
        var c = b.type;
        if (f[c]) b = f[c](a, b), b.type = c;
        else {
            if (b.create) b = b.create(a, b);
            else return print("UI Error: invalid element type " + a), null;
            b.rect || (b.rect = {
                x: b.x || 0,
                y: b.y || 0,
                width: 1,
                height: 1
            });
            b.drawStart ||
                (b.drawStart = function() {});
            b.draw || (b.draw = function() {})
        }
        return b
    };
    this.__age = 0;
    this.isDynamic = !0;
    this.setDynamic = function(a) {
        this.isDynamic = a
    };
    this.frame = function() {
        if (this.isDynamic || 0 == this.__age) 0 == this.__age % 20 && this.refreshDrawing(), 0 == this.__age % 3 && this.refreshElements();
        this.__age++
    };
    this.getElement = function(a) {
        return this.window.elementProvider.getElement(a)
    };
    this.getElementContent = function(a) {
        return this.content.elements[a]
    }
}

function WindowGroup() {
    this.windows = {};
    this.slotSource = null;
    this.setSlotSource = function(a) {
        this.slotSource = a;
        for (var b in this.windows) this.windows[b].setSlotSource(a)
    };
    this.open = function() {
        for (var a in this.windows) this.windows[a].openPrepare();
        var b = this;
        GuiUtils.Run(function() {
            for (var a in b.windows) b.windows[a].openFinal()
        })
    };
    this.close = function() {
        for (var a in this.windows) this.windows[a].close()
    };
    this.isOpened = function() {
        for (var a in this.windows)
            if (this.windows[a].isOpened()) return !0;
        return !1
    };
    this.addWindow = function(a, b) {
        var c = new WindowContent(b);
        this.windows[a] = c;
        this.slotSource && c.setSlotSource(this.slotSource);
        c.setWindowGroup(this);
        return c
    };
    this.getWindow = function(a) {
        return this.windows[a]
    };
    this.getWindowContent = function(a) {
        if (a = this.getWindow(a)) return a.content
    };
    this.setWindowContent = function(a, b) {
        var c = this.getWindow(a);
        c && c.setContent(b)
    };
    this.removeWindow = function(a) {
        var b = this.getWindow(a);
        b && (b.close(), delete this.windows[a])
    };
    this.refreshWindow = function(a) {
        (a = this.getWindow(a)) &&
        a.postRefresh()
    };
    this.refreshAll = function() {
        for (var a in this.windows) this.refreshWindow(a)
    }
}

function TileEntityWindow(a) {
    this.parent = WindowGroup;
    this.parent();
    this.addWindow("main");
    this.fromObject = this.setContent = function(a) {
        this.content = a || {};
        this.content.standart || (this.content.standart = null);
        this.setWindowContent("main", this.content)
    };
    this.setContent(a);
    a = GuiUtils.GetDisplaySize();
    var b = a[1] / a[0] * 1E3;
    this.mainWindowOffset = {
        x: 0,
        y: 0
    };
    this.setupHeader = function() {
        if (this.content.standart.header) {
            var a = this.content.standart.header.width || 80;
            this.mainWindowOffset.y = a - 20;
            var b = {
                location: {
                    x: 0,
                    y: 0,
                    width: 1E3,
                    height: a
                },
                params: this.content.params,
                drawing: [{
                    type: "background",
                    color: android.graphics.Color.BLACK
                }, {
                    type: "frame",
                    x: 0,
                    y: 0,
                    width: 1E3,
                    height: a,
                    scale: 3,
                    bg: this.content.standart.header.color || android.graphics.Color.rgb(114, 106, 112),
                    bitmap: this.content.standart.header.frame || "default_frame_7"
                }],
                elements: {}
            };
            this.content.standart.header.hideButton || (b.elements.__closeButton = {
                type: "closeButton",
                global: !0,
                sound: "random.click",
                x: 1E3 - .75 * a,
                y: 0,
                scale: a / 18 * .75
            });
            if (this.content.standart.header.text) {
                var e =
                    this.content.standart.header.text.font || {};
                b.drawing.push({
                    type: "text",
                    x: 500,
                    y: .6 * a,
                    text: this.content.standart.header.text.text,
                    size: e.size || .25 * a,
                    color: e.color || android.graphics.Color.WHITE,
                    shadow: e.shadow || .65,
                    alignCenter: !0
                })
            }
            this.addWindow("header", b).setDynamic(!1)
        }
    };
    this.setupInventory = function() {
        if (this.content.standart.inventory) {
            for (var a = this.content.standart.inventory.padding || 20, d = this.content.standart.inventory.width || 300, e = b - this.mainWindowOffset.y - 20 - 2 * a, f = {}, g = 0; 36 > g; g++) f["__invslot" +
                g] = {
                type: "invSlot",
                size: 251,
                x: g % 4 * 250,
                y: 250 * parseInt(g / 4),
                index: g + 9
            };
            this.addWindow("inventory", {
                location: {
                    x: this.mainWindowOffset.x + a,
                    y: this.mainWindowOffset.y + 20 + a,
                    width: d,
                    height: e,
                    scrollHeight: 2.25 * d
                },
                params: this.content.params,
                drawing: [{
                    type: "background",
                    color: android.graphics.Color.BLACK
                }],
                elements: f
            }).setDynamic(!1);
            this.getWindow("inventory").setRequireInventory(!0)
        }
    };
    this.setupBackground = function() {
        if (this.content.standart.background) {
            var a = this.content.standart.background,
                b = a.color,
                e = a.bitmap,
                f = a.frame;
            a.standart && (b = android.graphics.Color.rgb(149, 134, 129), f = {
                scale: 3
            }, e = void 0);
            var a = this.getWindow("main"),
                g = this.getWindowContent("main");
            g.drawing || (g.drawing = []);
            g = g.drawing;
            this.content.standart.header && !this.content.standart.header.hideShadow && g.unshift({
                type: "bitmap",
                x: 0,
                y: 15,
                bitmap: "_standart_header_shadow",
                scale: 2
            });
            f && g.unshift({
                type: "frame",
                x: 0,
                y: 0,
                width: a.getWidth(),
                height: a.getHeight(),
                bitmap: f.bitmap,
                scale: f.scale
            });
            e && (f = GuiWindowProvider.Images[e]) && g.unshift({
                type: "bitmap",
                x: 0,
                y: 0,
                bitmap: e,
                scale: 1E3 / f.width
            });
            "undefined" != b + "" && g.unshift({
                type: "background",
                color: b
            })
        }
    };
    this.openAll = this.open;
    this.open = function() {
        this.content.standart ? (this.setupHeader(), this.setupInventory(), this.getWindow("main").setLocation(this.mainWindowOffset.x, this.mainWindowOffset.y, 1E3 - this.mainWindowOffset.x, b - this.mainWindowOffset.y, this.content.standart.minHeight), this.setupBackground()) : this.getWindow("main").setFullscreen();
        this.openAll()
    }
}
var GuiAPI = {
        Container: Container,
        WindowProvider: GuiWindowProvider,
        WindowCore: Window,
        ElementProvider: GuiElementProvider,
        Window: WindowContent,
        WindowGroup: WindowGroup,
        StandartWindow: TileEntityWindow,
        Utils: GuiUtils,
        run: GuiUtils.Run,
        getMcContext: getMcContext,
        testUI: function(a) {
            var b = new Container;
            b.openAs(a);
            return b
        },
        openUI: function(a) {
            var b = new Container;
            b.openAs(a);
            return b
        },
        addIconOverride: function(a, b) {
            ItemIconSource.addOverride(a, b)
        },
        addItemOverride: function(a, b, c) {
            this.addIconOverride(a + "_" + b, c);
            0 == b && this.addIconOverride(a + "", c)
        },
        registerBitmap: function(a, b) {
            b && (GuiWindowProvider.Images[a] = b)
        },
        requireBitmap: function(a) {
            return GuiWindowProvider.Images[a]
        },
        getBitmapFromCache: function(a) {
            return GuiWindowProvider.Images[a]
        },
        getScreenHeight: function() {
            var a = GuiUtils.GetDisplaySize();
            return a[1] / a[0] * 1E3
        },
        checkAndPlacehold: function(a, b, c) {
            if (a && !this.requireBitmap(a)) {
                b = b || 1;
                c = c || 1;
                var d = ItemIconSource.getNamedIcon("missing_block");
                d ? (d = android.graphics.Bitmap.createScaledBitmap(d, b, c, !1), this.registerBitmap(a,
                    d), Logger.Log("texture " + a + " is missing placeholder created: " + b + "x" + c, "WARNING")) : Logger.Log("cannot create texture placeholder: standart prototype texture cannot be loaded", "ERROR")
            }
        },
        getSelectionName: function() {
            return GuiElementSelection.getSelection()
        }
    },
    TickingSettings = {
        runInThread: !0,
        threadPriority: -19,
        firstTick: !0
    };
Callback.addCallback("CoreConfigured", function(a) {
    a.access("perfomance.run_on_main_thread") ? setTickingThreadMode(!0) : setTickingThreadMode(!1);
    TickingThread.setPriority(a.access("perfomance.thread_priority"))
});

function modTick() {
    TickingThread.toQueue(threadTick);
    TickingThread.increaseTime();
    MainThread.exec()
}

function threadTick() {
    Callback.invokeCallback("tick");
    UpdatableAPI.updateAll();
    TileEntity.CheckTileEntities()
}
Callback.addCallback("NativeGuiChanged", function(a) {
    "pause_screen" == a ? (TickingThread.clear(), TickingThread.setPaused(!0), SavesFunctions.write(), Logger.Log("switched into pause mode, pausing current thread, saving data...", "CORE"), Logger.flush()) : TickingThread.isPaused() && (TickingThread.setPaused(!1), Logger.Log("exiting pause mode, unpausing current thread...", "CORE"))
});
var TickingThread_main = {
        time: 0,
        queue: [],
        priority: 0,
        pause: !1,
        running: !1,
        clear: function() {
            this.queue = []
        },
        resetTime: function() {
            this.time = 0
        },
        initThread: function(a) {
            this.priority = a || 0;
            this.running = !0;
            this.pause = !1;
            this.time = 0;
            this.clear()
        },
        threadLoop: function() {},
        setPaused: function(a) {
            this.pause = a
        },
        isPaused: function() {
            return this.pause
        },
        requestStop: function() {
            this.running = !1
        },
        toQueue: function(a) {
            if (this.running && !this.pause && a) try {
                a(this.time)
            } catch (b) {
                this.running = !1, a = Threading.formatFatalErrorMessage(b,
                    "mainThread", this.priority,
                    function() {
                        return "priority: " + TickingThread.priority + "\nrunning (paused): " + TickingThread.running + " (" + TickingThread.pause + ")\ntime (command time): " + TickingThread.time + " (" + TickingThread._time + ")\nqueue len: " + TickingThread.queue.length
                    }), GameAPI.dialogMessage(a, "FATAL ERROR")
            }
        },
        getTime: function() {
            return this.time
        },
        increaseTime: function() {
            this.time++
        },
        setPriority: function(a) {
            this.priority = parseInt(a) || 0;
            Logger.Log("main thread thread priority set to " + this.priority, "CORE")
        }
    },
    TickingThread_thread = {
        time: 0,
        _time: 0,
        queue: new java.util.ArrayList,
        priority: 0,
        pause: !1,
        running: !1,
        clear: function() {
            this.queue.clear()
        },
        resetTime: function() {
            this.time = this._time = 0
        },
        initThread: function(a) {
            Threading.getThread("tickingThread") || (this.priority = a || 0, this.running = !0, this.pause = !1, this.time = this._time = 0, this.clear(), Threading.initThread("tickingThread", function() {
                TickingThread.threadLoop()
            }, this.priority, !0, function() {
                return "priority: " + TickingThread.priority + "\nrunning (paused): " + TickingThread.running +
                    " (" + TickingThread.pause + ")\ntime (command time): " + TickingThread.time + " (" + TickingThread._time + ")\nqueue len: " + TickingThread.queue.length
            }))
        },
        threadLoop: function() {
            for (android.os.Process.setThreadPriority(this.priority); this.running;)
                if (this.time++, this.pause) java.lang.Thread.sleep(50);
                else if (0 < this.queue.size()) {
                var a = this.queue.get(0);
                this.queue.remove(0);
                this._time++;
                a && a();
                java.lang.Thread.yield()
            } else java.lang.Thread.sleep(50)
        },
        setPaused: function(a) {
            this.pause = a
        },
        isPaused: function() {
            return this.pause
        },
        requestStop: function() {
            this.running = !1
        },
        toQueue: function(a) {
            512 < this.queue.size() && this.clear();
            a.time = this.time;
            this.queue.add(a)
        },
        getTime: function() {
            return this._time
        },
        increaseTime: function() {
            this.time++
        },
        setPriority: function(a) {
            this.priority = parseInt(a) || 0;
            Logger.Log("thicking thread priority set to " + this.priority, "CORE")
        }
    },
    TickingThread = TickingThread_main;

function setTickingThreadMode(a) {
    a ? (TickingThread = TickingThread_main, Logger.Log("switched Core Engine into main thread mode", "CORE")) : (TickingThread = TickingThread_thread, Logger.Log("switched Core Engine into alternative thread mode", "CORE"))
}
var MainThread = {
    stack: [],
    push: function(a) {
        this.stack.push(a)
    },
    exec: function() {
        for (; 0 < this.stack.length;) try {
            var a = this.stack.shift();
            a && a()
        } catch (c) {
            Logger.Log("main thread error occured: ", "ERROR");
            Logger.LogError(c);
            var b = Threading.formatFatalErrorMessage(c, "mainThread", this.priority, function() {
                return "priority: " + TickingThread.priority + "\nrunning (paused): " + TickingThread.running + " (" + TickingThread.pause + ")\ntime (command time): " + TickingThread.time + " (" + TickingThread._time + ")\nqueue len: " + TickingThread.queue.length
            });
            GameAPI.dialogMessage(b, "FATAL ERROR");
            TickingThread.requestStop()
        }
    }
};

function newLevel() {
    Callback.invokeCallback("LevelSelected");
    ResetInGameAPIs();
    SavesFunctions.read();
    TickingThread.initThread();
    Callback.invokeCallback("LevelPreLoaded");
    Callback.invokeCallback("LevelLoaded")
}

function leaveGame() {
    TickingThread.requestStop();
    TickingThread.resetTime();
    Callback.invokeCallback("LevelLeft");
    SavesFunctions.write();
    ResetInGameAPIs()
}

function selectLevelHook() {
    Callback.invokeCallback("LevelSelected")
}

function destroyBlock(a, b, c, d) {
    a = parseInt(a);
    b = parseInt(b);
    c = parseInt(c);
    d = {
        x: a,
        y: b,
        z: c,
        side: d,
        relative: {
            x: a,
            y: b,
            z: c
        }
    };
    switch (d.side) {
        case 0:
            d.relative.y--;
            break;
        case 1:
            d.relative.y++;
            break;
        case 2:
            d.relative.z--;
            break;
        case 3:
            d.relative.z++;
            break;
        case 4:
            d.relative.x--;
            break;
        case 5:
            d.relative.x++
    }
    a = UnlimitedAPIAccess.getFullTile(a, b, c);
    Callback.invokeCallback("DestroyBlock", d, a, getPlayerEnt())
}

function startDestroyBlock(a, b, c, d) {
    a = parseInt(a);
    b = parseInt(b);
    c = parseInt(c);
    d = {
        x: a,
        y: b,
        z: c,
        side: d,
        relative: {
            x: a,
            y: b,
            z: c
        }
    };
    switch (d.side) {
        case 0:
            d.relative.y--;
            break;
        case 1:
            d.relative.y++;
            break;
        case 2:
            d.relative.z--;
            break;
        case 3:
            d.relative.z++;
            break;
        case 4:
            d.relative.x--;
            break;
        case 5:
            d.relative.x++
    }
    a = UnlimitedAPIAccess.getFullTile(a, b, c);
    Callback.invokeCallback("DestroyBlockStart", d, a, getPlayerEnt())
}

function continueDestroyBlock(a, b, c, d, e) {
    a = parseInt(a);
    b = parseInt(b);
    c = parseInt(c);
    d = {
        x: a,
        y: b,
        z: c,
        side: d,
        relative: {
            x: a,
            y: b,
            z: c
        }
    };
    switch (d.side) {
        case 0:
            d.relative.y--;
            break;
        case 1:
            d.relative.y++;
            break;
        case 2:
            d.relative.z--;
            break;
        case 3:
            d.relative.z++;
            break;
        case 4:
            d.relative.x--;
            break;
        case 5:
            d.relative.x++
    }
    a = UnlimitedAPIAccess.getFullTile(a, b, c);
    Callback.invokeCallback("DestroyBlockContinue", d, a, e, getPlayerEnt())
}

function explodeHook(a, b, c, d, e, f) {
    Callback.invokeCallback("Explosion", {
        x: b,
        y: c,
        z: d
    }, {
        entity: a,
        power: e,
        onFire: f
    })
}

function redstoneUpdateHook(a, b, c, d, e, f, g) {
    d = {
        power: d || 0,
        booleanPar: e
    };
    e = {
        x: a,
        y: b,
        z: c
    };
    a = UnlimitedAPIAccess.getFullTile(a, b, c);
    Callback.invokeCallback("RedstoneSignal", e, d, a)
}

function procCmd(a) {
    var b;
    a = a.trim();
    Callback.invokeCallback("NativeCommand", a);
    a = a.split(" ");
    if ("c" == a.shift()) {
        "maxupdates" == a[0] && (b = parseInt(a[1])) && (UpdatableAPI.setMaxUpdateCalls(b), clientMessage("set maximum update calls to " + UpdatableAPI.maximumCalls));
        "gm" == a[0] && (b = parseInt(a[1]), Level.setGameMode(b));
        if ("give" == a[0]) {
            var c = parseInt(a[1]) || 0;
            b = parseInt(a[1]) || 64;
            var d = parseInt(a[1]) || 0;
            addItemInventory(c, b, d)
        }
        "log" == a[0] && Logger.showAsDialog("loading log", "");
        "save" == a[0] && (Logger.Log("saving data by command...",
            "CORE"), SavesFunctions.write(), "debug" == a[1] && GameAPI.dialogMessage(JSON.stringify(DataSaver.dataObject, null, "\t"), "saves"))
    }
}

function chatHook(a) {
    Callback.invokeCallback("ClientChat", a);
    a.startsWith("-c ") ? (a = a.substring(3, a.length), Callback.invokeCallback("CoreCommand", a, a.split(" "))) : a.startsWith("- ") && (a = a.substring(2, a.length), Callback.invokeCallback("Command", a, a.split(" ")))
}

function serverMessageReceiveHook(a) {
    Callback.invokeCallback("ServerChat", a)
}
Callback.addCallback("CoreCommand", function(a, b) {});

function canTileBeReplaced(a) {
    return {
        0: !0,
        8: !0,
        9: !0,
        10: !0,
        11: !0,
        31: !0
    }[a] || !1
}

function doesVanillaTileHasUI(a) {
    var b = {
        23: !0,
        54: !0,
        58: !0,
        61: !0,
        62: !0,
        64: !0,
        69: !0,
        77: !0,
        96: !0,
        116: !0,
        145: !0,
        158: !0
    };
    return !Entity.isSneaking(getPlayerEnt()) && b[a]
}

function useItem(a, b, c, d, e, f, g, h) {
    var k = Player.getCarriedItemCount();
    d = UnlimitedAPI.GetUID(d, g);
    k = {
        id: d.id,
        count: k,
        data: d.data
    };
    h = UnlimitedAPI.GetUID(e, h);
    h = {
        id: h.id,
        data: h.data
    };
    a = {
        x: a,
        y: b,
        z: c,
        side: f,
        relative: {
            x: a,
            y: b,
            z: c
        }
    };
    if (!canTileBeReplaced(e)) switch (a.side) {
        case 0:
            a.relative.y--;
            break;
        case 1:
            a.relative.y++;
            break;
        case 2:
            a.relative.z--;
            break;
        case 3:
            a.relative.z++;
            break;
        case 4:
            a.relative.x--;
            break;
        case 5:
            a.relative.x++
    }
    Callback.invokeCallback("ItemUse", a, k, h)
}

function setPlayerItem(a, b, c) {
    UnlimitedAPIAccess.setPlayerCarriedItem(a, b, c)
}
Callback.addCallback("ItemUse", function(a, b, c) {
    var d, e = BlockRegistry.getPlaceFunc(b.id);
    if (TileEntity.isTileEntityBlock(c.id) && ((d = TileEntity.getTileEntity(a.x, a.y, a.z)) || (d = TileEntity.addTileEntity(a.x, a.y, a.z)), d && d.onItemClick(b.id, b.count, b.data, a))) {
        preventDefault();
        return
    }
    if (!doesVanillaTileHasUI(c.id)) {
        if (TileEntity.isTileEntityBlock(b.id)) {
            if (d = getTile(a.relative.x, a.relative.y, a.relative.z), canTileBeReplaced(d)) {
                e ? (a = e(a, b, c) || a.relative, TileEntity.addTileEntity(a.x, a.y, a.z)) : (setTile(a.relative.x,
                    a.relative.y, a.relative.z, b.id), TileEntity.addTileEntity(a.relative.x, a.relative.y, a.relative.z));
                setPlayerItem(b.id, b.count - 1, b.data);
                preventDefault();
                return
            }
        } else e && (e(a, b, c), setPlayerItem(b.id, b.count - 1, b.data), preventDefault());
        ItemRegistry.onItemUsed(a, b, c)
    }
});

function attackHook(a, b) {
    Callback.invokeCallback("PlayerAttack", a, b)
}
var EntityDataRegistry = {
    isLevelLoaded: !1,
    entityData: {},
    entityDataTyped: {},
    getAllData: function() {
        return this.entityData
    },
    getDataForType: function(a) {
        this.entityDataTyped[a] || (this.entityDataTyped[a] = {});
        return this.entityDataTyped[a]
    },
    entityAdded: function(a) {
        var b = Entity.getEntityTypeId(a);
        this.entityData[a] = {
            type: b
        };
        this.getDataForType(b)[a] = a;
        this.isLevelLoaded ? Callback.invokeCallback("EntityAdded", a, b) : this.delayedAddCallbacks.push(a)
    },
    entityRemoved: function(a) {
        var b = Entity.getEntityTypeId(a);
        Callback.invokeCallback("EntityRemoved",
            a, b);
        delete this.entityData[a];
        delete this.getDataForType(b)[a]
    },
    resetEngine: function() {
        this.entityData = {};
        this.entityDataTyped = {};
        this.delayedAddCallbacks = []
    },
    delayedAddCallbacks: [],
    setLevelLoaded: function(a) {
        if (this.isLevelLoaded = a) {
            for (var b in this.delayedAddCallbacks) a = this.delayedAddCallbacks[b], Callback.invokeCallback("EntityAdded", a, Entity.getEntityTypeId(a));
            this.delayedAddCallbacks = []
        }
    },
    getData: function(a) {
        return this.entityData[a] || {
            type: 0,
            name: "none"
        }
    },
    getType: function(a) {
        return this.getData(a).type
    }
};
Callback.addCallback("LevelLoaded", function() {
    EntityDataRegistry.setLevelLoaded(!0)
});
Callback.addCallback("LevelLeft", function() {
    EntityDataRegistry.setLevelLoaded(!1)
});

function entityAddedHook(a) {
    60 > WorldAPI.getThreadTime() && 9E3 < Entity.getHealth(a) ? Entity.remove(a) : EntityDataRegistry.entityAdded(a)
}

function entityRemovedHook(a) {
    EntityDataRegistry.entityRemoved(a)
}

function deathHook(a, b) {
    -1 == a && (a = null);
    Callback.invokeCallback("EntityDeath", b, a)
}

function entityHurtHook(a, b, c) {
    -1 == a && (a = null);
    Callback.invokeCallback("EntityHurt", a, b, c)
}

function projectileHitBlockHook(a, b, c, d, e) {
    b = parseInt(b);
    c = parseInt(c);
    d = parseInt(d);
    e = {
        x: b,
        y: c,
        z: d,
        side: e,
        relative: {
            x: b,
            y: c,
            z: d
        }
    };
    switch (e.side) {
        case 0:
            e.relative.y--;
            break;
        case 1:
            e.relative.y++;
            break;
        case 2:
            e.relative.z--;
            break;
        case 3:
            e.relative.z++;
            break;
        case 4:
            e.relative.x--;
            break;
        case 5:
            e.relative.x++
    }
    b = UnlimitedAPIAccess.getFullTile(b, c, d);
    Callback.invokeCallback("ProjectileHitBlock", a, e, b);
    b = EntityAPI.getPosition(a);
    b.block = e;
    Callback.invokeCallback("ProjectileHit", a, ProjectileItemRegistry.getItem(a),
        b)
}

function projectileHitEntityHook(a, b) {
    var c = EntityAPI.getPosition(a);
    Callback.invokeCallback("ProjectileHitEntity", a, b);
    Callback.invokeCallback("ProjectileHit", a, ProjectileItemRegistry.getItem(a), {
        x: c.x,
        y: c.y,
        z: c.z,
        entity: b
    })
}
var ProjectileItemRegistry = {
    data: {},
    registerProjectile: function(a) {
        3 > EntityAPI.getDistanceToEntity(a, getPlayerEnt()) && (this.data[a] = PlayerAPI.getCarriedItem())
    },
    registerProjectileRemoval: function(a) {
        this.data[a] && delete this.data[a]
    },
    getItem: function(a) {
        return this.data[a]
    }
};
Callback.addCallback("EntityAdded", function(a) {
    81 == Entity.getEntityTypeId(a) && ProjectileItemRegistry.registerProjectile(a)
});
Callback.addCallback("EntityRemoved", function(a) {
    81 == Entity.getEntityTypeId(a) && ProjectileItemRegistry.registerProjectileRemoval(a)
});

function eatHook(a, b) {
    Callback.invokeCallback("FoodEaten", a, b)
}

function screenChangeHook(a) {
    Callback.invokeCallback("NativeGuiChanged", a)
}

function playerAddExpHook(a, b) {
    Callback.invokeCallback("ExpAdd", b, a)
}

function playerExpLevelChangeHook(a, b) {
    Callback.invokeCallback("ExpLevelAdd", b, a)
}
var PCWorkbenchUIScreen = new GuiAPI.StandartWindow;
PCWorkbenchUIScreen.setContent({
    standart: {
        inventory: {
            standart: !0
        },
        header: {
            text: {
                text: "Workbench (PC) - Core Engine"
            }
        },
        background: {
            standart: !0
        }
    },
    drawing: [{
        type: "bitmap",
        bitmap: "_workbench_bar",
        x: 664,
        y: 144,
        scale: 2
    }],
    elements: {
        slot0: {
            type: "slot",
            x: 350,
            y: 60,
            size: 94
        },
        slot1: {
            type: "slot",
            x: 450,
            y: 60,
            size: 94
        },
        slot2: {
            type: "slot",
            x: 550,
            y: 60,
            size: 94
        },
        slot3: {
            type: "slot",
            x: 350,
            y: 160,
            size: 94
        },
        slot4: {
            type: "slot",
            x: 450,
            y: 160,
            size: 94
        },
        slot5: {
            type: "slot",
            x: 550,
            y: 160,
            size: 94
        },
        slot6: {
            type: "slot",
            x: 350,
            y: 260,
            size: 94
        },
        slot7: {
            type: "slot",
            x: 450,
            y: 260,
            size: 94
        },
        slot8: {
            type: "slot",
            x: 550,
            y: 260,
            size: 94
        },
        resultSlot: {
            type: "slot",
            x: 820,
            y: 157,
            size: 100,
            drawEveryTick: !0,
            clicker: {
                onClick: function(a, b, c) {
                    a = b.getSlot("resultSlot");
                    NativeWorkbench.onItemCrafed(a, b) && (addItemInventory(a.id, a.count, a.data), a.id = a.count = a.data = 0)
                },
                onLongClick: function(a, b, c) {
                    this.onClick(a, b, c)
                }
            }
        }
    }
});
var PEWorkbenchUIScreen = new GuiAPI.StandartWindow;
PEWorkbenchUIScreen.setContent({
    standart: {
        header: {
            text: {
                text: "Workbench (PE) - Core Engine"
            }
        },
        background: {
            standart: !0
        }
    },
    drawing: [{
        type: "bitmap",
        bitmap: "_workbench_bar",
        x: 664,
        y: 144,
        scale: 2
    }],
    elements: {
        slot0: {
            type: "slot",
            x: 350,
            y: 60,
            size: 94,
            visual: !0,
            showAnyCount: !0
        },
        slot1: {
            type: "slot",
            x: 450,
            y: 60,
            size: 94,
            visual: !0,
            showAnyCount: !0
        },
        slot2: {
            type: "slot",
            x: 550,
            y: 60,
            size: 94,
            visual: !0,
            showAnyCount: !0
        },
        slot3: {
            type: "slot",
            x: 350,
            y: 160,
            size: 94,
            visual: !0,
            showAnyCount: !0
        },
        slot4: {
            type: "slot",
            x: 450,
            y: 160,
            size: 94,
            visual: !0,
            showAnyCount: !0
        },
        slot5: {
            type: "slot",
            x: 550,
            y: 160,
            size: 94,
            visual: !0,
            showAnyCount: !0
        },
        slot6: {
            type: "slot",
            x: 350,
            y: 260,
            size: 94,
            visual: !0,
            showAnyCount: !0
        },
        slot7: {
            type: "slot",
            x: 450,
            y: 260,
            size: 94,
            visual: !0,
            showAnyCount: !0
        },
        slot8: {
            type: "slot",
            x: 550,
            y: 260,
            size: 94,
            visual: !0,
            showAnyCount: !0
        },
        resultSlot: {
            type: "slot",
            x: 820,
            y: 157,
            size: 100,
            drawEveryTick: !0,
            clicker: {
                onClick: function(a, b, c) {
                    WorkbenchPocketStyle.provideSelectedRecipe()
                },
                onLongClick: function(a, b, c) {
                    this.onClick(a, b, c)
                }
            }
        }
    }
});
PEWorkbenchUIScreen.addWindow("possible-recipes", {
    location: {
        x: 20,
        y: 100,
        width: 300,
        height: GuiAPI.getScreenHeight() - 120
    },
    drawing: [{
        type: "background",
        color: android.graphics.Color.rgb(24, 21, 21)
    }]
}).setDynamic(!1);
var PEWorkbenchUIScreen_splitted = new GuiAPI.StandartWindow;
PEWorkbenchUIScreen_splitted.setContent({
    standart: {
        header: {
            text: {
                text: "Workbench (PE/s) - Core Engine"
            }
        },
        background: {
            standart: !0
        }
    },
    drawing: [],
    elements: {
        slot0: {
            type: "slot",
            x: 537,
            y: 100,
            size: 75,
            visual: !0,
            showAnyCount: !0
        },
        slot1: {
            type: "slot",
            x: 612,
            y: 100,
            size: 75,
            visual: !0,
            showAnyCount: !0
        },
        slot2: {
            type: "slot",
            x: 687,
            y: 100,
            size: 75,
            visual: !0,
            showAnyCount: !0
        },
        slot3: {
            type: "slot",
            x: 537,
            y: 175,
            size: 75,
            visual: !0,
            showAnyCount: !0
        },
        slot4: {
            type: "slot",
            x: 612,
            y: 175,
            size: 75,
            visual: !0,
            showAnyCount: !0
        },
        slot5: {
            type: "slot",
            x: 687,
            y: 175,
            size: 75,
            visual: !0,
            showAnyCount: !0
        },
        slot6: {
            type: "slot",
            x: 537,
            y: 250,
            size: 75,
            visual: !0,
            showAnyCount: !0
        },
        slot7: {
            type: "slot",
            x: 612,
            y: 250,
            size: 75,
            visual: !0,
            showAnyCount: !0
        },
        slot8: {
            type: "slot",
            x: 687,
            y: 250,
            size: 75,
            visual: !0,
            showAnyCount: !0
        },
        craftButton: {
            type: "button",
            bitmap: "_craft_button_up",
            bitmap2: "_craft_button_down",
            x: 545,
            y: 330,
            scale: 4.375,
            sound: "random.click",
            isTextButton: !0,
            textOffset: {
                x: 120,
                y: 50
            },
            text: "",
            font: {
                size: 20,
                color: android.graphics.Color.WHITE,
                shadow: .6
            },
            clicker: {
                onClick: function(a,
                    b, c) {
                    WorkbenchPocketStyle.provideSelectedRecipe()
                },
                onLongClick: function(a, b, c) {
                    this.onClick(a, b, c)
                }
            }
        },
        resultSlot: {
            type: "slot",
            x: 552,
            y: 333,
            size: 80,
            bitmap: "_default_slot_invis",
            visual: !0,
            drawEveryTick: !0
        }
    }
});
PEWorkbenchUIScreen_splitted.addWindow("possible-recipes", {
    location: {
        x: 20,
        y: 100,
        width: 300,
        height: GuiAPI.getScreenHeight() - 120,
        scrollHeight: 710
    },
    drawing: [{
        type: "background",
        color: android.graphics.Color.rgb(24, 21, 21)
    }, {
        type: "bitmap",
        x: 333.3,
        y: 0,
        bitmap: "button_blank_48x24",
        scale: 333.3 / 48
    }],
    elements: {
        buttonPrev: {
            type: "button",
            x: 0,
            y: 0,
            bitmap: "button_prev_48x24",
            bitmap2: "button_prev_48x24p",
            scale: 333.3 / 48,
            sound: "random.click",
            clicker: {
                onClick: function() {
                    WorkbenchPocketStyle.switchPage(-1, !0)
                }
            }
        },
        buttonNext: {
            type: "button",
            x: 666.6,
            y: 0,
            bitmap: "button_next_48x24",
            bitmap2: "button_next_48x24p",
            scale: 333.3 / 48,
            sound: "random.click",
            clicker: {
                onClick: function() {
                    WorkbenchPocketStyle.switchPage(1, !0)
                }
            }
        },
        pageText: {
            type: "text",
            x: 400,
            y: 29,
            width: 250,
            height: 105,
            text: "  0/0 ",
            font: {
                size: 60,
                color: android.graphics.Color.WHITE,
                shadow: .7
            }
        }
    }
}).setDynamic(!1);
Callback.addCallback("PostLoaded", function() {});
var NativeWorkbench = {
    container: null,
    recipes: {},
    ignoreDamageData: {},
    openFor: function(a) {
        this.container = new Container;
        this.container.openAs(PCWorkbenchUIScreen);
        UpdatableAPI.addUpdatable({
            container: this.container,
            time: 0,
            update: function() {
                var a = this.container.getSlot("resultSlot");
                if (!this.container.isOpened()) a.id = a.count = a.data = 0, this.container.dropAt(getPlayerX(), getPlayerY(), getPlayerZ()), this.remove = !0;
                else if (0 == this.time++ % 8) {
                    var c = NativeWorkbench.getFieldData(this.container);
                    (c = NativeWorkbench.getRecipeByField(c)) &&
                    NativeWorkbench.checkRecipePrefix(c, "") ? (this.container.setText("debug", c.recipeResult.count + " of " + Item.getName(c.recipeResult.id, c.recipeResult.data, !0)), a.id = c.recipeResult.id, a.count = c.recipeResult.count, a.data = c.recipeResult.data) : (this.container.setText("debug", ""), a.id = a.count = a.data = 0)
                }
            }
        })
    },
    checkRecipePrefix: function(a, b) {
        return a && a.prefix && -1 == (b + "").indexOf(a.prefix + "") ? !1 : !0
    },
    onItemCrafed: function(a, b, c) {
        if (b != this.container) return Logger.Log("Error in processing recipe: containers do not match",
            "ERROR"), !1;
        var d = NativeWorkbench.getFieldData(this.container);
        b = this.getRecipeByField(d);
        if (!b || !this.checkRecipePrefix(b, c)) return !1;
        c = {
            container: this.container,
            field: "shaped" == b.type ? d.pattern : d.shapeless,
            result: a,
            prevented: !1,
            prevent: function() {
                this.prevented = !0
            },
            decreaseFieldSlot: function(a) {
                this.field[a] && 0 < this.field[a].count && this.field[a].count--;
                this.container.validateSlot("slot" + a)
            }
        };
        this.__recipeFunc = b.recipeFunc || this.basicRecipeFunc;
        this.__recipeFunc(c, c.field, a);
        this.container.validateAll();
        return !c.prevented
    },
    basicRecipeFunc: function(a, b, c) {
        for (c = 0; c < b.length; c++) a.decreaseFieldSlot(c)
    },
    getFieldData: function(a) {
        for (var b = {
                pattern: [],
                shapeless: []
            }, c = 0; 9 > c; c++) {
            var d = a.getSlot("slot" + c);
            b.pattern[c] = d;
            0 < d.id && b.shapeless.push(d)
        }
        for (a = 0; a < b.shapeless.length; a++)
            for (c = 0; c < b.shapeless.length - 1; c++) b.shapeless[c].id > b.shapeless[c + 1].id && (d = b.shapeless[c], b.shapeless[c] = b.shapeless[c + 1], b.shapeless[c + 1] = d);
        b.shapelessMask = {};
        for (a in b.shapeless) b.shapelessMask[b.shapeless[a].id + ":" + b.shapeless[a].data] =
            (b.shapelessMask[b.shapeless[a].id + ":" + b.shapeless[a].data] || 0) + 1, b.shapelessMask[b.shapeless[a].id + ":-1"] = (b.shapelessMask[b.shapeless[a].id + ":-1"] || 0) + 1;
        c = [];
        d = [];
        for (a in b.pattern) c.push(b.pattern[a].id);
        for (a in b.shapeless) d.push(b.shapeless[a].id);
        b.patternKey = c.join("|");
        b.shapelessKey = "s" + d.join("|");
        return b
    },
    getRecipeByField: function(a) {
        var b = this.recipes[a.patternKey];
        if (b)
            for (var c in b) {
                var d = b[c].recipeSource;
                var e = !0;
                for (var f in d)
                    if (a.pattern[f].id != d[f].id || -1 != d[f].data && d[f].data !=
                        a.pattern[f].data) {
                        e = !1;
                        break
                    }
                if (e) return b[c]
            }
        if (b = this.recipes[a.shapelessKey]) {
            for (c in b) {
                d = b[c];
                e = !0;
                for (f in d.recipeSource) {
                    var g = d.recipeSource[f].id + ":" + d.recipeSource[f].data;
                    if (!a.shapelessMask[g] || 0 > a.shapelessMask[g]) {
                        e = !1;
                        break
                    }
                    a.shapelessMask[g]--
                }
                if (e) return d
            }
            return null
        }
    },
    addShapedRecipe: function(a, b, c, d, e) {
        for (var f, g = {}, h = 0; h < c.length; h += 3) g[c[h]] = {
            id: c[h + 1],
            data: c[h + 2]
        };
        c = Math.min(3, b[0].length);
        for (var k = Math.min(3, b.length), m = 4 - c, l = 4 - k, n = 0; n < m; n++)
            for (var r = 0; r < l; r++) {
                var p = [null, null, null, null, null, null, null, null, null];
                for (f = 0; f < c; f++)
                    for (var q = 0; q < k; q++) p[n + f + 3 * (r + q)] = g[b[q].charAt(f)];
                q = [];
                for (h in p) f = p[h] || {
                    id: 0,
                    data: 0
                }, p[h] = f, q.push(f.id);
                q = q.join("|");
                this.recipes[q] || (this.recipes[q] = []);
                var t = [];
                for (h in p) f = p[h] || {
                    id: 0,
                    data: 0
                }, t.push(f.id + ":" + f.data);
                f = t.join("|");
                this.recipes[q].push({
                    type: "shaped",
                    shortKey: q,
                    strKey: f,
                    recipeSource: p,
                    recipeResult: a,
                    recipeFunc: d,
                    prefix: e,
                    offset: {
                        x: n,
                        y: r
                    }
                })
            }
    },
    addShapelessRecipe: function(a, b, c, d) {
        for (var e = 0; e < b.length; e++)
            for (var f =
                    0; f < b.length - 1; f++)
                if (b[f].id > b[f + 1].id) {
                    var g = b[f];
                    b[f] = b[f + 1];
                    b[f + 1] = g
                }
        f = [];
        for (e in b) f.push(b[e].id);
        e = "s" + f.join("|");
        this.recipes[e] || (this.recipes[e] = []);
        a = {
            type: "shapeless",
            shortKey: e,
            strKey: JSON.stringify(b),
            recipeSource: b,
            recipeResult: a,
            recipeFunc: c,
            prefix: d
        };
        this.recipes[e].push(a)
    },
    clearItemRecipes: function(a) {
        for (var b in this.recipes) {
            var c = this.recipes[b],
                d;
            for (d in c) {
                var e = c[d].recipeResult;
                e.id == a.id && e.count == a.count && e.data == a.data && c.splice(d--, 1)
            }
        }
    }
};
Callback.addCallback("ItemUse", function(a, b, c) {
    58 != c.id || Entity.isSneaking(getPlayerEnt()) || (preventDefault(), coreEngineConfig.access("util.pocket_workbench_style") ? WorkbenchPocketStyle.openUI() : NativeWorkbench.openFor(a))
});
var WorkbenchPocketStyle = {
    isSplittedStyle: !0,
    getInventoryData: function() {
        for (var a, b = [], c = 0; 36 > c; c++) b[c] = PlayerInventorySlotSource.getSource(c + 9);
        if (this.container)
            for (c = 0; 9 > c; c++) a = this.container.getSlot("slot" + c), b[c + 36] = {
                id: a.id,
                count: a.count,
                data: a.data
            };
        PlayerInventorySlotSource.refresh();
        var d = {},
            e = {},
            f = {};
        for (c in b) a = b[c], 0 < a.id && ("undefined" == f[a.id] + "" && (f[a.id] = a.data || 0), d[a.id] = (d[a.id] || 0) + a.count, e[a.id + ":-1"] = (e[a.id + ":-1"] || 0) + a.count, e[a.id + ":" + a.data] = (e[a.id + ":" + a.data] || 0) + a.count);
        return {
            items: d,
            itemsWithData: e,
            dataByID: f
        }
    },
    getVisibleRecipes: function() {
        var a, b = this.getInventoryData(),
            c = b.items,
            b = b.itemsWithData,
            d = [];
        for (a in NativeWorkbench.recipes)
            for (var e in c) - 1 != a.indexOf(e) && d.push(NativeWorkbench.recipes[a]);
        c = [];
        e = [];
        for (var f in d)
            for (var g in d[f]) {
                var h = d[f][g];
                if (!(h.prefix || h.offset && (0 < h.offset.x || 0 < h.offset.y))) {
                    var k = !0,
                        m = !1,
                        l;
                    for (l in h.recipeSource)(a = h.recipeSource[l]) && 0 < a.id && (a = a.id + ":" + a.data, b[a] ? m = !0 : k = !1);
                    k ? c[h.strKey] = h : m && (e[h.strKey] = h)
                }
            }
        g = [];
        for (f in c) g.push({
            recipe: c[f],
            possible: !0
        });
        for (f in e) g.push({
            recipe: e[f],
            possible: !1
        });
        return {
            visible: e,
            possible: c,
            all: g
        }
    },
    openUI: function() {
        this.currentPage = 0;
        this.container = new Container;
        this.refreshUI(this.currentPage);
        this.container.openAs(this.isSplittedStyle ? PEWorkbenchUIScreen_splitted : PEWorkbenchUIScreen);
        UpdatableAPI.addUpdatable({
            container: this.container,
            time: 0,
            update: function() {
                this.container.getSlot("resultSlot");
                this.container.isOpened() || (WorkbenchPocketStyle.deselectCurrent(), this.remove = !0)
            }
        })
    },
    currentPage: 0,
    currentMaxPage: 0,
    switchPage: function(a, b) {
        this.currentMaxPage = this.currentMaxPage || 1;
        this.currentPage = b ? (this.currentPage + a + this.currentMaxPage) % this.currentMaxPage : a % this.currentMaxPage;
        this.refreshUI(this.currentPage)
    },
    selectRecipeClicker: function(a) {
        return {
            onClick: function() {
                WorkbenchPocketStyle.selectRecipe(a)
            }
        }
    },
    refreshUI: function(a) {
        var b = this.getVisibleRecipes().all,
            c = this.isSplittedStyle ? PEWorkbenchUIScreen_splitted : PEWorkbenchUIScreen,
            d = c.getWindowContent("possible-recipes").elements;
        for (k in d) k.startsWith("craft") &&
            (d[k] = null);
        var e = this.isSplittedStyle ? 166.6 : 0,
            f = 0,
            g;
        for (g in b)
            if (f++, !this.isSplittedStyle || !(g < 36 * a || g >= 36 * (a + 1))) {
                var h = b[g];
                var k = "craft" + g;
                var m = 250 * parseInt(g % 4),
                    l = 250 * (this.isSplittedStyle ? parseInt(g / 4) % 9 : parseInt(g / 4)) + e;
                d[k] = {
                    type: "slot",
                    x: m,
                    y: l,
                    size: 250,
                    bitmap: h.possible ? "_default_slot" : "_default_slot_dark",
                    clicker: this.selectRecipeClicker(h.recipe)
                };
                h = h.recipe.recipeResult;
                this.container.setSlot(k, h.id, h.count, h.data)
            }
        this.isSplittedStyle ? (k = Math.floor(f / 36 + .999), b = a + 1 + "/" + k, 9 > a && (b = " " +
            b), 10 > k && (b = " " + b), d.pageText.text = b, this.currentMaxPage = k) : PEWorkbenchUIScreen.getWindowContent("possible-recipes").location.scrollHeight = 75 * parseInt(f / 4 + 4);
        c.getWindow("possible-recipes").postElementRefresh()
    },
    refreshUIThreaded: function() {
        Threading.initThread("workbench-recipe-refresh", function() {
            WorkbenchPocketStyle.refreshUI(WorkbenchPocketStyle.currentPage)
        }, 20)
    },
    selectRecipe: function(a) {
        this.deselectCurrent();
        this.selectedRecipe = a;
        this.isFirstCrafted = !0;
        var b = a.recipeSource,
            c = PlayerAPI.getInventory();
        c.refreshInv();
        var d = {},
            e = {},
            f = [],
            g;
        for (g in b) {
            var h = b[g];
            var k = c.getFullItem(h.id, 9999, h.data, !0);
            h = k.id + ":" + k.data; - 1 == k.data ? h = d[h] || h : d[k.id + ":-1"] = h;
            f[g] = h;
            e[h] ? (e[h].count += k.count, e[h].amount++) : e[h] = {
                num: 0,
                amount: 1,
                count: k.count,
                id: k.id,
                data: k.data
            }
        }
        c.applyInv();
        for (g in b) b = this.container.getSlot("slot" + g), h = f[g], h = e[h], c = parseInt(h.count / h.amount), d = h.num++ < h.count % h.amount ? 1 : 0, b.count = c + d, b.id = h.id, b.data = Math.max(0, h.data);
        e = this.container.getSlot("resultSlot");
        e.id = a.recipeResult.id;
        e.count = 1;
        e.data = a.recipeResult.data;
        this.container.setText("craftButton", "x" + a.recipeResult.count)
    },
    deselectCurrent: function() {
        var a = PlayerAPI.getInventory();
        a.refreshInv();
        for (var b = 0; 9 > b; b++) {
            var c = this.container.getSlot("slot" + b);
            0 < c.id && 0 < c.count && a.addItem(c.id, c.count, c.data, !0);
            this.container.clearSlot("slot" + b)
        }
        a.applyInv()
    },
    provideSelectedRecipe: function() {
        if (this.container && this.selectedRecipe) {
            for (var a = 0; 9 > a; a++) this.container.validateSlot("slot" + a);
            var a = RecipeRegistry.getRecipeResult(this.container),
                b = this.selectedRecipe.recipeResult;
            b && a && a.id == b.id && a.count == b.count && a.data == b.data && (a = RecipeRegistry.provideRecipe(this.container)) && (PlayerAPI.addItemToInventory(a.id, a.count, a.data), this.isFirstCrafted && (this.isFirstCrafted = !1, this.refreshUIThreaded()))
        }
    }
};
Callback.addCallback("CoreConfigured", function(a) {
    WorkbenchPocketStyle.isSplittedStyle = a.access("util.split_pocket_workbench_to_pages")
});
NativeWorkbench.addShapedRecipe({
    id: 270,
    count: 1,
    data: 0
}, ["XXX", " # ", " # "], ["#", 280, 0, "X", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 269,
    count: 1,
    data: 0
}, ["X", "#", "#"], ["#", 280, 0, "X", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 271,
    count: 1,
    data: 0
}, ["XX", "X#", " #"], ["#", 280, 0, "X", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 290,
    count: 1,
    data: 0
}, ["XX", " #", " #"], ["#", 280, 0, "X", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 274,
    count: 1,
    data: 0
}, ["XXX", " # ", " # "], ["#", 280, 0, "X", 4, 0]);
NativeWorkbench.addShapedRecipe({
    id: 273,
    count: 1,
    data: 0
}, ["X", "#", "#"], ["#", 280, 0, "X", 4, 0]);
NativeWorkbench.addShapedRecipe({
    id: 275,
    count: 1,
    data: 0
}, ["XX", "X#", " #"], ["#", 280, 0, "X", 4, 0]);
NativeWorkbench.addShapedRecipe({
    id: 291,
    count: 1,
    data: 0
}, ["XX", " #", " #"], ["#", 280, 0, "X", 4, 0]);
NativeWorkbench.addShapedRecipe({
    id: 257,
    count: 1,
    data: 0
}, ["XXX", " # ", " # "], ["#", 280, 0, "X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 256,
    count: 1,
    data: 0
}, ["X", "#", "#"], ["#", 280, 0, "X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 258,
    count: 1,
    data: 0
}, ["XX", "X#", " #"], ["#", 280, 0, "X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 292,
    count: 1,
    data: 0
}, ["XX", " #", " #"], ["#", 280, 0, "X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 278,
    count: 1,
    data: 0
}, ["XXX", " # ", " # "], ["#", 280, 0, "X", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 277,
    count: 1,
    data: 0
}, ["X", "#", "#"], ["#", 280, 0, "X", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 279,
    count: 1,
    data: 0
}, ["XX", "X#", " #"], ["#", 280, 0, "X", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 293,
    count: 1,
    data: 0
}, ["XX", " #", " #"], ["#", 280, 0, "X", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 285,
    count: 1,
    data: 0
}, ["XXX", " # ", " # "], ["#", 280, 0, "X", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 284,
    count: 1,
    data: 0
}, ["X", "#", "#"], ["#", 280, 0, "X", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 286,
    count: 1,
    data: 0
}, ["XX", "X#", " #"], ["#", 280, 0, "X", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 294,
    count: 1,
    data: 0
}, ["XX", " #", " #"], ["#", 280, 0, "X", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 359,
    count: 1,
    data: 0
}, [" #", "# "], ["#", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 268,
    count: 1,
    data: 0
}, ["X", "X", "#"], ["#", 280, 0, "X", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 272,
    count: 1,
    data: 0
}, ["X", "X", "#"], ["#", 280, 0, "X", 4, 0]);
NativeWorkbench.addShapedRecipe({
    id: 267,
    count: 1,
    data: 0
}, ["X", "X", "#"], ["#", 280, 0, "X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 276,
    count: 1,
    data: 0
}, ["X", "X", "#"], ["#", 280, 0, "X", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 283,
    count: 1,
    data: 0
}, ["X", "X", "#"], ["#", 280, 0, "X", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 261,
    count: 1,
    data: 0
}, [" #X", "# X", " #X"], ["X", 287, 0, "#", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 262,
    count: 4,
    data: 0
}, ["X", "#", "Y"], ["Y", 288, 0, "X", 318, 0, "#", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 41,
    count: 1,
    data: 0
}, ["###", "###", "###"], ["#", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 266,
    count: 9,
    data: 0
}, ["#"], ["#", 41, 0]);
NativeWorkbench.addShapedRecipe({
    id: 42,
    count: 1,
    data: 0
}, ["###", "###", "###"], ["#", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 265,
    count: 9,
    data: 0
}, ["#"], ["#", 42, 0]);
NativeWorkbench.addShapedRecipe({
    id: 57,
    count: 1,
    data: 0
}, ["###", "###", "###"], ["#", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 264,
    count: 9,
    data: 0
}, ["#"], ["#", 57, 0]);
NativeWorkbench.addShapedRecipe({
    id: 133,
    count: 1,
    data: 0
}, ["###", "###", "###"], ["#", 388, 0]);
NativeWorkbench.addShapedRecipe({
    id: 388,
    count: 9,
    data: 0
}, ["#"], ["#", 133, 0]);
NativeWorkbench.addShapedRecipe({
    id: 152,
    count: 1,
    data: 0
}, ["###", "###", "###"], ["#", 331, 0]);
NativeWorkbench.addShapedRecipe({
    id: 331,
    count: 9,
    data: 0
}, ["#"], ["#", 152, 0]);
NativeWorkbench.addShapedRecipe({
    id: 22,
    count: 1,
    data: 0
}, ["###", "###", "###"], ["#", 351, 4]);
NativeWorkbench.addShapedRecipe({
    id: 351,
    count: 9,
    data: 4
}, ["#"], ["#", 22, 0]);
NativeWorkbench.addShapedRecipe({
    id: 170,
    count: 1,
    data: 0
}, ["###", "###", "###"], ["#", 296, 0]);
NativeWorkbench.addShapedRecipe({
    id: 296,
    count: 9,
    data: 0
}, ["#"], ["#", 170, 0]);
NativeWorkbench.addShapedRecipe({
    id: 173,
    count: 1,
    data: 0
}, ["###", "###", "###"], ["#", 263, 0]);
NativeWorkbench.addShapedRecipe({
    id: 263,
    count: 9,
    data: 0
}, ["#"], ["#", 173, 0]);
NativeWorkbench.addShapedRecipe({
    id: 266,
    count: 1,
    data: 0
}, ["###", "###", "###"], ["#", 371, 0]);
NativeWorkbench.addShapedRecipe({
    id: 371,
    count: 9,
    data: 0
}, ["#"], ["#", 266, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 282,
    count: 1,
    data: 0
}, [{
    id: 39,
    data: 0
}, {
    id: 40,
    data: 0
}, {
    id: 281,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 459,
    count: 1,
    data: 0
}, ["BBB", "BBB", " # "], ["B", 457, 0, "#", 281, 0]);
NativeWorkbench.addShapedRecipe({
    id: 357,
    count: 8,
    data: 0
}, ["#X#"], ["X", 351, 3, "#", 296, 0]);
NativeWorkbench.addShapedRecipe({
    id: 103,
    count: 1,
    data: 0
}, ["MMM", "MMM", "MMM"], ["M", 360, 0]);
NativeWorkbench.addShapedRecipe({
    id: 362,
    count: 1,
    data: 0
}, ["M"], ["M", 360, 0]);
NativeWorkbench.addShapedRecipe({
    id: 361,
    count: 4,
    data: 0
}, ["M"], ["M", 86, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 400,
    count: 1,
    data: 0
}, [{
    id: 86,
    data: 0
}, {
    id: 353,
    data: 0
}, {
    id: 344,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 376,
    count: 1,
    data: 0
}, ["RB", " #"], ["R", 375, 0, "B", 353, 0, "#", 39, 0]);
NativeWorkbench.addShapedRecipe({
    id: 54,
    count: 1,
    data: 0
}, ["###", "# #", "###"], ["#", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 146,
    count: 1,
    data: 0
}, ["TC"], ["C", 54, 0, "T", 131, 0]);
NativeWorkbench.addShapedRecipe({
    id: 61,
    count: 1,
    data: 0
}, ["###", "# #", "###"], ["#", 4, 0]);
NativeWorkbench.addShapedRecipe({
    id: 58,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 24,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 12, 0]);
NativeWorkbench.addShapedRecipe({
    id: 179,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 12, 1]);
NativeWorkbench.addShapedRecipe({
    id: 24,
    count: 4,
    data: 2
}, ["##", "##"], ["#", 24, 0]);
NativeWorkbench.addShapedRecipe({
    id: 179,
    count: 4,
    data: 2
}, ["##", "##"], ["#", 179, 0]);
NativeWorkbench.addShapedRecipe({
    id: 24,
    count: 1,
    data: 1
}, ["#", "#"], ["#", 44, 1]);
NativeWorkbench.addShapedRecipe({
    id: 179,
    count: 1,
    data: 1
}, ["#", "#"], ["#", 182, 0]);
NativeWorkbench.addShapedRecipe({
    id: 98,
    count: 4,
    data: 0
}, ["##", "##"], ["#", 1, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 98,
    count: 1,
    data: 1
}, [{
    id: 98,
    data: 0
}, {
    id: 106,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 98,
    count: 1,
    data: 3
}, ["S", "S"], ["S", 44, 5]);
NativeWorkbench.addShapelessRecipe({
    id: 48,
    count: 1,
    data: 0
}, [{
    id: 4,
    data: 0
}, {
    id: 106,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 101,
    count: 16,
    data: 0
}, ["###", "###"], ["#", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 102,
    count: 16,
    data: 0
}, ["###", "###"], ["#", 20, 0]);
NativeWorkbench.addShapedRecipe({
    id: 112,
    count: 1,
    data: 0
}, ["NN", "NN"], ["N", 405, 0]);
NativeWorkbench.addShapedRecipe({
    id: 155,
    count: 1,
    data: 0
}, ["NN", "NN"], ["N", 406, 0]);
NativeWorkbench.addShapedRecipe({
    id: 155,
    count: 1,
    data: 1
}, ["#", "#"], ["#", 44, 6]);
NativeWorkbench.addShapedRecipe({
    id: 155,
    count: 2,
    data: 2
}, ["#", "#"], ["#", 155, 0]);
NativeWorkbench.addShapedRecipe({
    id: 1,
    count: 2,
    data: 3
}, ["CQ", "QC"], ["C", 4, 0, "Q", 406, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 1,
    count: 1,
    data: 1
}, [{
    id: 1,
    data: 3
}, {
    id: 406,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 1,
    count: 2,
    data: 5
}, [{
    id: 1,
    data: 3
}, {
    id: 4,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 1,
    count: 4,
    data: 4
}, ["SS", "SS"], ["S", 1, 3]);
NativeWorkbench.addShapedRecipe({
    id: 1,
    count: 4,
    data: 2
}, ["SS", "SS"], ["S", 1, 1]);
NativeWorkbench.addShapedRecipe({
    id: 1,
    count: 4,
    data: 6
}, ["SS", "SS"], ["S", 1, 5]);
NativeWorkbench.addShapedRecipe({
    id: 298,
    count: 1,
    data: 0
}, ["XXX", "X X"], ["X", 334, 0]);
NativeWorkbench.addShapedRecipe({
    id: 299,
    count: 1,
    data: 0
}, ["X X", "XXX", "XXX"], ["X", 334, 0]);
NativeWorkbench.addShapedRecipe({
    id: 300,
    count: 1,
    data: 0
}, ["XXX", "X X", "X X"], ["X", 334, 0]);
NativeWorkbench.addShapedRecipe({
    id: 301,
    count: 1,
    data: 0
}, ["X X", "X X"], ["X", 334, 0]);
NativeWorkbench.addShapedRecipe({
    id: 306,
    count: 1,
    data: 0
}, ["XXX", "X X"], ["X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 307,
    count: 1,
    data: 0
}, ["X X", "XXX", "XXX"], ["X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 308,
    count: 1,
    data: 0
}, ["XXX", "X X", "X X"], ["X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 309,
    count: 1,
    data: 0
}, ["X X", "X X"], ["X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 310,
    count: 1,
    data: 0
}, ["XXX", "X X"], ["X", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 311,
    count: 1,
    data: 0
}, ["X X", "XXX", "XXX"], ["X", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 312,
    count: 1,
    data: 0
}, ["XXX", "X X", "X X"], ["X", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 313,
    count: 1,
    data: 0
}, ["X X", "X X"], ["X", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 314,
    count: 1,
    data: 0
}, ["XXX", "X X"], ["X", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 315,
    count: 1,
    data: 0
}, ["X X", "XXX", "XXX"], ["X", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 316,
    count: 1,
    data: 0
}, ["XXX", "X X", "X X"], ["X", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 317,
    count: 1,
    data: 0
}, ["X X", "X X"], ["X", 266, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 15
}, [{
    id: 351,
    data: 0
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 14
}, [{
    id: 351,
    data: 1
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 13
}, [{
    id: 351,
    data: 2
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 12
}, [{
    id: 351,
    data: 3
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 11
}, [{
    id: 351,
    data: 4
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 10
}, [{
    id: 351,
    data: 5
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 9
}, [{
    id: 351,
    data: 6
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 8
}, [{
    id: 351,
    data: 7
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 7
}, [{
    id: 351,
    data: 8
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 6
}, [{
    id: 351,
    data: 9
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 5
}, [{
    id: 351,
    data: 10
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 4
}, [{
    id: 351,
    data: 11
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 3
}, [{
    id: 351,
    data: 12
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 2
}, [{
    id: 351,
    data: 13
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 1
}, [{
    id: 351,
    data: 14
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 35,
    count: 1,
    data: 0
}, [{
    id: 351,
    data: 15
}, {
    id: 35,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 351,
    count: 1,
    data: 11
}, ["#"], ["#", 37, 0]);
NativeWorkbench.addShapedRecipe({
    id: 351,
    count: 2,
    data: 1
}, ["#"], ["#", 244, 0]);
NativeWorkbench.addShapedRecipe({
    id: 351,
    count: 1,
    data: 1
}, ["#"], ["#", 38, 0]);
NativeWorkbench.addShapedRecipe({
    id: 351,
    count: 3,
    data: 15
}, ["#"], ["#", 352, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 9
}, [{
    id: 351,
    data: 1
}, {
    id: 351,
    data: 15
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 14
}, [{
    id: 351,
    data: 1
}, {
    id: 351,
    data: 11
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 10
}, [{
    id: 351,
    data: 2
}, {
    id: 351,
    data: 15
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 8
}, [{
    id: 351,
    data: 0
}, {
    id: 351,
    data: 15
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 7
}, [{
    id: 351,
    data: 8
}, {
    id: 351,
    data: 15
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 3,
    data: 7
}, [{
    id: 351,
    data: 0
}, {
    id: 351,
    data: 15
}, {
    id: 351,
    data: 15
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 3
}, [{
    id: 351,
    data: 0
}, {
    id: 351,
    data: 1
}, {
    id: 351,
    data: 11
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 12
}, [{
    id: 351,
    data: 4
}, {
    id: 351,
    data: 15
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 6
}, [{
    id: 351,
    data: 4
}, {
    id: 351,
    data: 2
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 5
}, [{
    id: 351,
    data: 4
}, {
    id: 351,
    data: 1
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 13
}, [{
    id: 351,
    data: 5
}, {
    id: 351,
    data: 9
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 3,
    data: 13
}, [{
    id: 351,
    data: 4
}, {
    id: 351,
    data: 1
}, {
    id: 351,
    data: 9
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 4,
    data: 13
}, [{
    id: 351,
    data: 4
}, {
    id: 351,
    data: 15
}, {
    id: 351,
    data: 1
}, {
    id: 351,
    data: 1
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 1,
    data: 12
}, [{
    id: 38,
    data: 1
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 1,
    data: 13
}, [{
    id: 38,
    data: 2
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 1,
    data: 7
}, [{
    id: 38,
    data: 3
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 1,
    data: 1
}, [{
    id: 38,
    data: 4
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 1,
    data: 14
}, [{
    id: 38,
    data: 5
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 1,
    data: 7
}, [{
    id: 38,
    data: 6
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 1,
    data: 9
}, [{
    id: 38,
    data: 7
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 1,
    data: 7
}, [{
    id: 38,
    data: 8
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 11
}, [{
    id: 175,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 13
}, [{
    id: 175,
    data: 1
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 1
}, [{
    id: 175,
    data: 4
}]);
NativeWorkbench.addShapelessRecipe({
    id: 351,
    count: 2,
    data: 9
}, [{
    id: 175,
    data: 5
}]);
NativeWorkbench.addShapedRecipe({
    id: 395,
    count: 1,
    data: 1
}, ["###", "###", "###"], ["#", 339, 0]);
NativeWorkbench.addShapedRecipe({
    id: 395,
    count: 1,
    data: 2
}, ["###", "#W#", "###"], ["#", 339, 0, "W", 345, 0]);
NativeWorkbench.addShapedRecipe({
    id: 339,
    count: 3,
    data: 0
}, ["###"], ["#", 338, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 340,
    count: 1,
    data: 0
}, [{
    id: 339,
    data: 0
}, {
    id: 339,
    data: 0
}, {
    id: 339,
    data: 0
}, {
    id: 334,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 139,
    count: 6,
    data: 0
}, ["###", "###"], ["#", 4, 0]);
NativeWorkbench.addShapedRecipe({
    id: 139,
    count: 6,
    data: 1
}, ["###", "###"], ["#", 48, 0]);
NativeWorkbench.addShapedRecipe({
    id: 113,
    count: 6,
    data: 0
}, ["###", "###"], ["#", 112, 0]);
NativeWorkbench.addShapedRecipe({
    id: 85,
    count: 3,
    data: 0
}, ["W#W", "W#W"], ["#", 280, 0, "W", 5, 0]);
NativeWorkbench.addShapedRecipe({
    id: 85,
    count: 3,
    data: 1
}, ["W#W", "W#W"], ["#", 280, 0, "W", 5, 1]);
NativeWorkbench.addShapedRecipe({
    id: 85,
    count: 3,
    data: 2
}, ["W#W", "W#W"], ["#", 280, 0, "W", 5, 2]);
NativeWorkbench.addShapedRecipe({
    id: 85,
    count: 3,
    data: 3
}, ["W#W", "W#W"], ["#", 280, 0, "W", 5, 3]);
NativeWorkbench.addShapedRecipe({
    id: 85,
    count: 3,
    data: 4
}, ["W#W", "W#W"], ["#", 280, 0, "W", 5, 4]);
NativeWorkbench.addShapedRecipe({
    id: 85,
    count: 3,
    data: 5
}, ["W#W", "W#W"], ["#", 280, 0, "W", 5, 5]);
NativeWorkbench.addShapedRecipe({
    id: 107,
    count: 1,
    data: 0
}, ["#W#", "#W#"], ["#", 280, 0, "W", 5, 0]);
NativeWorkbench.addShapedRecipe({
    id: 183,
    count: 1,
    data: 0
}, ["#W#", "#W#"], ["#", 280, 0, "W", 5, 1]);
NativeWorkbench.addShapedRecipe({
    id: 184,
    count: 1,
    data: 0
}, ["#W#", "#W#"], ["#", 280, 0, "W", 5, 2]);
NativeWorkbench.addShapedRecipe({
    id: 185,
    count: 1,
    data: 0
}, ["#W#", "#W#"], ["#", 280, 0, "W", 5, 3]);
NativeWorkbench.addShapedRecipe({
    id: 187,
    count: 1,
    data: 0
}, ["#W#", "#W#"], ["#", 280, 0, "W", 5, 4]);
NativeWorkbench.addShapedRecipe({
    id: 186,
    count: 1,
    data: 0
}, ["#W#", "#W#"], ["#", 280, 0, "W", 5, 5]);
NativeWorkbench.addShapedRecipe({
    id: 145,
    count: 1,
    data: 0
}, ["###", " X ", "XXX"], ["#", 42, 0, "X", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 47,
    count: 1,
    data: 0
}, ["###", "XXX", "###"], ["#", 5, -1, "X", 340, 0]);
NativeWorkbench.addShapedRecipe({
    id: 80,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 332, 0]);
NativeWorkbench.addShapedRecipe({
    id: 78,
    count: 6,
    data: 0
}, ["###"], ["#", 80, 0]);
NativeWorkbench.addShapedRecipe({
    id: 82,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 337, 0]);
NativeWorkbench.addShapedRecipe({
    id: 45,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 336, 0]);
NativeWorkbench.addShapedRecipe({
    id: 89,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 348, 0]);
NativeWorkbench.addShapedRecipe({
    id: 35,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 287, 0]);
NativeWorkbench.addShapedRecipe({
    id: 46,
    count: 1,
    data: 0
}, ["X#X", "#X#", "X#X"], ["X", 289, 0, "#", 12, 0]);
NativeWorkbench.addShapedRecipe({
    id: 44,
    count: 6,
    data: 3
}, ["###"], ["#", 4, 0]);
NativeWorkbench.addShapedRecipe({
    id: 44,
    count: 6,
    data: 0
}, ["###"], ["#", 1, 0]);
NativeWorkbench.addShapedRecipe({
    id: 44,
    count: 6,
    data: 1
}, ["###"], ["#", 24, 0]);
NativeWorkbench.addShapedRecipe({
    id: 182,
    count: 6,
    data: 0
}, ["###"], ["#", 179, 0]);
NativeWorkbench.addShapedRecipe({
    id: 158,
    count: 6,
    data: 0
}, ["###"], ["#", 5, 0]);
NativeWorkbench.addShapedRecipe({
    id: 158,
    count: 6,
    data: 1
}, ["###"], ["#", 5, 1]);
NativeWorkbench.addShapedRecipe({
    id: 158,
    count: 6,
    data: 2
}, ["###"], ["#", 5, 2]);
NativeWorkbench.addShapedRecipe({
    id: 158,
    count: 6,
    data: 3
}, ["###"], ["#", 5, 3]);
NativeWorkbench.addShapedRecipe({
    id: 158,
    count: 6,
    data: 4
}, ["###"], ["#", 5, 4]);
NativeWorkbench.addShapedRecipe({
    id: 158,
    count: 6,
    data: 5
}, ["###"], ["#", 5, 5]);
NativeWorkbench.addShapedRecipe({
    id: 44,
    count: 6,
    data: 4
}, ["###"], ["#", 45, 0]);
NativeWorkbench.addShapedRecipe({
    id: 44,
    count: 6,
    data: 5
}, ["###"], ["#", 98, 0]);
NativeWorkbench.addShapedRecipe({
    id: 44,
    count: 6,
    data: 7
}, ["###"], ["#", 112, 0]);
NativeWorkbench.addShapedRecipe({
    id: 44,
    count: 6,
    data: 6
}, ["###"], ["#", 155, 0]);
NativeWorkbench.addShapedRecipe({
    id: 65,
    count: 3,
    data: 0
}, ["# #", "###", "# #"], ["#", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 324,
    count: 3,
    data: 0
}, ["##", "##", "##"], ["#", 5, 0]);
NativeWorkbench.addShapedRecipe({
    id: 427,
    count: 3,
    data: 0
}, ["##", "##", "##"], ["#", 5, 1]);
NativeWorkbench.addShapedRecipe({
    id: 428,
    count: 3,
    data: 0
}, ["##", "##", "##"], ["#", 5, 2]);
NativeWorkbench.addShapedRecipe({
    id: 429,
    count: 3,
    data: 0
}, ["##", "##", "##"], ["#", 5, 3]);
NativeWorkbench.addShapedRecipe({
    id: 430,
    count: 3,
    data: 0
}, ["##", "##", "##"], ["#", 5, 4]);
NativeWorkbench.addShapedRecipe({
    id: 431,
    count: 3,
    data: 0
}, ["##", "##", "##"], ["#", 5, 5]);
NativeWorkbench.addShapedRecipe({
    id: 96,
    count: 2,
    data: 0
}, ["###", "###"], ["#", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 167,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 131,
    count: 2,
    data: 0
}, ["I", "S", "W"], ["I", 265, 0, "S", 280, 0, "W", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 25,
    count: 1,
    data: 0
}, ["WWW", "WRW", "WWW"], ["R", 331, 0, "W", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 330,
    count: 3,
    data: 0
}, ["##", "##", "##"], ["#", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 323,
    count: 3,
    data: 0
}, ["###", "###", " X "], ["#", 5, -1, "X", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 354,
    count: 1,
    data: 0
}, ["AAA", "BEB", "CCC"], ["A", 325, 1, "B", 353, 0, "C", 296, 0, "E", 344, 0], function(a, b) {
    for (var c = 0; 9 > c; c++) 3 > c ? b[c].data = 0 : a.decreaseFieldSlot(c)
});
NativeWorkbench.addShapedRecipe({
    id: 353,
    count: 1,
    data: 0
}, ["#"], ["#", 338, 0]);
NativeWorkbench.addShapedRecipe({
    id: 396,
    count: 1,
    data: 0
}, ["###", "#X#", "###"], ["#", 371, 0, "X", 391, 0]);
NativeWorkbench.addShapedRecipe({
    id: 382,
    count: 1,
    data: 0
}, ["###", "#X#", "###"], ["#", 371, 0, "X", 360, 0]);
NativeWorkbench.addShapedRecipe({
    id: 377,
    count: 2,
    data: 0
}, ["#"], ["#", 369, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 378,
    count: 1,
    data: 0
}, [{
    id: 377,
    data: 0
}, {
    id: 341,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 376,
    count: 1,
    data: 0
}, [{
    id: 39,
    data: 0
}, {
    id: 353,
    data: 0
}, {
    id: 375,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 5,
    count: 4,
    data: 0
}, ["#"], ["#", 17, 0]);
NativeWorkbench.addShapedRecipe({
    id: 5,
    count: 4,
    data: 1
}, ["#"], ["#", 17, 1]);
NativeWorkbench.addShapedRecipe({
    id: 5,
    count: 4,
    data: 2
}, ["#"], ["#", 17, 2]);
NativeWorkbench.addShapedRecipe({
    id: 5,
    count: 4,
    data: 3
}, ["#"], ["#", 17, 3]);
NativeWorkbench.addShapedRecipe({
    id: 5,
    count: 4,
    data: 4
}, ["#"], ["#", 162, 0]);
NativeWorkbench.addShapedRecipe({
    id: 5,
    count: 4,
    data: 5
}, ["#"], ["#", 162, 1]);
NativeWorkbench.addShapedRecipe({
    id: 280,
    count: 4,
    data: 0
}, ["#", "#"], ["#", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 50,
    count: 4,
    data: 0
}, ["X", "#"], ["X", 263, 0, "#", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 50,
    count: 4,
    data: 0
}, ["X", "#"], ["X", 263, 1, "#", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 281,
    count: 4,
    data: 0
}, ["# #", " # "], ["#", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 413,
    count: 1,
    data: 0
}, [" R ", "CPM", " B "], ["R", 412, 0, "C", 391, 0, "P", 393, 0, "M", 39, 0, "B", 281, 0]);
NativeWorkbench.addShapedRecipe({
    id: 413,
    count: 1,
    data: 0
}, [" R ", "CPM", " B "], ["R", 412, 0, "C", 391, 0, "P", 393, 0, "M", 40, 0, "B", 281, 0]);
NativeWorkbench.addShapedRecipe({
    id: 374,
    count: 3,
    data: 0
}, ["# #", " # "], ["#", 20, 0]);
NativeWorkbench.addShapedRecipe({
    id: 390,
    count: 1,
    data: 0
}, ["# #", " # "], ["#", 336, 0]);
NativeWorkbench.addShapedRecipe({
    id: 66,
    count: 16,
    data: 0
}, ["X X", "X#X", "X X"], ["X", 265, 0, "#", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 27,
    count: 6,
    data: 0
}, ["X X", "X#X", "XRX"], ["X", 266, 0, "R", 331, 0, "#", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 28,
    count: 6,
    data: 0
}, ["X X", "X#X", "XRX"], ["X", 265, 0, "R", 331, 0, "#", 70, 0]);
NativeWorkbench.addShapedRecipe({
    id: 126,
    count: 6,
    data: 0
}, ["XSX", "XRX", "XSX"], ["X", 265, 0, "R", 76, 0, "S", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 328,
    count: 1,
    data: 0
}, ["# #", "###"], ["#", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 342,
    count: 1,
    data: 0
}, ["C", "M"], ["C", 54, 0, "M", 328, 0]);
NativeWorkbench.addShapedRecipe({
    id: 408,
    count: 1,
    data: 0
}, ["H", "M"], ["H", 410, 0, "M", 328, 0]);
NativeWorkbench.addShapedRecipe({
    id: 380,
    count: 1,
    data: 0
}, ["# #", "# #", "###"], ["#", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 379,
    count: 1,
    data: 0
}, [" B ", "###"], ["#", 4, 0, "B", 369, 0]);
NativeWorkbench.addShapedRecipe({
    id: 91,
    count: 1,
    data: 0
}, ["A", "B"], ["A", 86, 0, "B", 50, 0]);
NativeWorkbench.addShapedRecipe({
    id: 333,
    count: 1,
    data: 0
}, ["#P#", "###"], ["#", 5, 0, "P", 269, 0]);
NativeWorkbench.addShapedRecipe({
    id: 333,
    count: 1,
    data: 1
}, ["#P#", "###"], ["#", 5, 1, "P", 269, 0]);
NativeWorkbench.addShapedRecipe({
    id: 333,
    count: 1,
    data: 2
}, ["#P#", "###"], ["#", 5, 2, "P", 269, 0]);
NativeWorkbench.addShapedRecipe({
    id: 333,
    count: 1,
    data: 3
}, ["#P#", "###"], ["#", 5, 3, "P", 269, 0]);
NativeWorkbench.addShapedRecipe({
    id: 333,
    count: 1,
    data: 4
}, ["#P#", "###"], ["#", 5, 4, "P", 269, 0]);
NativeWorkbench.addShapedRecipe({
    id: 333,
    count: 1,
    data: 5
}, ["#P#", "###"], ["#", 5, 5, "P", 269, 0]);
NativeWorkbench.addShapedRecipe({
    id: 325,
    count: 1,
    data: 0
}, ["# #", " # "], ["#", 265, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 259,
    count: 1,
    data: 0
}, [{
    id: 265,
    data: 0
}, {
    id: 318,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 297,
    count: 1,
    data: 0
}, ["###"], ["#", 296, 0]);
NativeWorkbench.addShapedRecipe({
    id: 53,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 5, 0]);
NativeWorkbench.addShapedRecipe({
    id: 134,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 5, 1]);
NativeWorkbench.addShapedRecipe({
    id: 135,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 5, 2]);
NativeWorkbench.addShapedRecipe({
    id: 136,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 5, 3]);
NativeWorkbench.addShapedRecipe({
    id: 163,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 5, 4]);
NativeWorkbench.addShapedRecipe({
    id: 164,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 5, 5]);
NativeWorkbench.addShapedRecipe({
    id: 67,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 4, 0]);
NativeWorkbench.addShapedRecipe({
    id: 108,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 45, 0]);
NativeWorkbench.addShapedRecipe({
    id: 128,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 24, 0]);
NativeWorkbench.addShapedRecipe({
    id: 180,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 179, 0]);
NativeWorkbench.addShapedRecipe({
    id: 109,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 98, 0]);
NativeWorkbench.addShapedRecipe({
    id: 156,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 155, 0]);
NativeWorkbench.addShapedRecipe({
    id: 114,
    count: 4,
    data: 0
}, ["#  ", "## ", "###"], ["#", 112, 0]);
NativeWorkbench.addShapedRecipe({
    id: 346,
    count: 1,
    data: 0
}, ["  #", " #X", "# X"], ["#", 280, 0, "X", 287, 0]);
NativeWorkbench.addShapedRecipe({
    id: 398,
    count: 1,
    data: 0
}, ["# ", " X"], ["#", 346, 0, "X", 391, 0]);
NativeWorkbench.addShapedRecipe({
    id: 321,
    count: 1,
    data: 0
}, ["###", "#X#", "###"], ["#", 280, 0, "X", 35, 0]);
NativeWorkbench.addShapedRecipe({
    id: 322,
    count: 1,
    data: 0
}, ["###", "#X#", "###"], ["#", 266, 0, "X", 260, 0]);
NativeWorkbench.addShapedRecipe({
    id: 466,
    count: 1,
    data: 1
}, ["###", "#X#", "###"], ["#", 41, 0, "X", 260, 0]);
NativeWorkbench.addShapedRecipe({
    id: 69,
    count: 1,
    data: 0
}, ["X", "#"], ["#", 4, 0, "X", 280, 0]);
NativeWorkbench.addShapedRecipe({
    id: 76,
    count: 1,
    data: 0
}, ["X", "#"], ["#", 280, 0, "X", 331, 0]);
NativeWorkbench.addShapedRecipe({
    id: 151,
    count: 1,
    data: 0
}, ["GGG", "QQQ", "WWW"], ["G", 20, 0, "Q", 406, 0, "W", 158, 0]);
NativeWorkbench.addShapedRecipe({
    id: 356,
    count: 1,
    data: 0
}, ["#X#", "III"], ["#", 76, 0, "X", 331, 0, "I", 1, 0]);
NativeWorkbench.addShapedRecipe({
    id: 123,
    count: 1,
    data: 0
}, [" X ", "X#X", " X "], ["X", 331, 0, "#", 89, 0]);
NativeWorkbench.addShapedRecipe({
    id: 347,
    count: 1,
    data: 0
}, [" # ", "#X#", " # "], ["#", 266, 0, "X", 331, 0]);
NativeWorkbench.addShapedRecipe({
    id: 345,
    count: 1,
    data: 0
}, [" # ", "#X#", " # "], ["#", 265, 0, "X", 331, 0]);
NativeWorkbench.addShapedRecipe({
    id: 77,
    count: 1,
    data: 5
}, ["#"], ["#", 1, 0]);
NativeWorkbench.addShapedRecipe({
    id: 143,
    count: 1,
    data: 5
}, ["#"], ["#", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 70,
    count: 1,
    data: 0
}, ["##"], ["#", 1, 0]);
NativeWorkbench.addShapedRecipe({
    id: 72,
    count: 1,
    data: 0
}, ["##"], ["#", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 147,
    count: 1,
    data: 0
}, ["GG"], ["G", 266, 0]);
NativeWorkbench.addShapedRecipe({
    id: 148,
    count: 1,
    data: 0
}, ["II"], ["I", 265, 0]);
NativeWorkbench.addShapedRecipe({
    id: 23,
    count: 1,
    data: 3
}, ["###", "#X#", "#R#"], ["#", 4, 0, "X", 261, 0, "R", 331, 0]);
NativeWorkbench.addShapedRecipe({
    id: 125,
    count: 1,
    data: 3
}, ["###", "# #", "#R#"], ["#", 4, 0, "R", 331, 0]);
NativeWorkbench.addShapedRecipe({
    id: 410,
    count: 1,
    data: 0
}, ["I I", "ICI", " I "], ["I", 265, 0, "C", 54, 0]);
NativeWorkbench.addShapedRecipe({
    id: 251,
    count: 1,
    data: 0
}, ["###", "RRQ", "###"], ["#", 4, 0, "Q", 406, 0, "R", 331, 0]);
NativeWorkbench.addShapedRecipe({
    id: 33,
    count: 1,
    data: 0
}, ["TTT", "#X#", "#R#"], ["#", 4, 0, "X", 265, 0, "R", 331, 0, "T", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 29,
    count: 1,
    data: 0
}, ["S", "P"], ["S", 341, 0, "P", 33, 0]);
NativeWorkbench.addShapedRecipe({
    id: 355,
    count: 1,
    data: 0
}, ["###", "XXX"], ["#", 35, 0, "X", 5, -1]);
NativeWorkbench.addShapedRecipe({
    id: 116,
    count: 1,
    data: 0
}, [" B ", "D#D", "###"], ["#", 49, 0, "B", 340, 0, "D", 264, 0]);
NativeWorkbench.addShapedRecipe({
    id: 334,
    count: 1,
    data: 0
}, ["##", "##"], ["#", 415, 0]);
NativeWorkbench.addShapedRecipe({
    id: 404,
    count: 1,
    data: 0
}, [" # ", "#X#", "III"], ["#", 76, 0, "X", 406, 0, "I", 1, 0]);
NativeWorkbench.addShapedRecipe({
    id: 407,
    count: 1,
    data: 0
}, ["#", "X"], ["#", 46, 0, "X", 328, 0]);
NativeWorkbench.addShapedRecipe({
    id: 389,
    count: 1,
    data: 0
}, ["###", "#X#", "###"], ["#", 280, 0, "X", 334, 0]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 0
}, ["##"], ["#", 35, 0]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 15
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 0]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 1
}, ["##"], ["#", 35, 1]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 14
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 1]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 2
}, ["##"], ["#", 35, 2]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 13
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 2]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 3
}, ["##"], ["#", 35, 3]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 12
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 3]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 4
}, ["##"], ["#", 35, 4]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 11
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 4]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 5
}, ["##"], ["#", 35, 5]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 10
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 5]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 6
}, ["##"], ["#", 35, 6]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 9
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 6]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 7
}, ["##"], ["#", 35, 7]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 8
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 7]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 8
}, ["##"], ["#", 35, 8]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 7
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 8]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 9
}, ["##"], ["#", 35, 9]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 6
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 9]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 10
}, ["##"], ["#", 35, 10]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 5
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 10]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 11
}, ["##"], ["#", 35, 11]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 4
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 11]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 12
}, ["##"], ["#", 35, 12]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 3
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 12]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 13
}, ["##"], ["#", 35, 13]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 2
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 13]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 14
}, ["##"], ["#", 35, 14]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 1
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 14]);
NativeWorkbench.addShapedRecipe({
    id: 171,
    count: 3,
    data: 15
}, ["##"], ["#", 35, 15]);
NativeWorkbench.addShapedRecipe({
    id: 159,
    count: 8,
    data: 0
}, ["###", "#X#", "###"], ["#", 172, 0, "X", 351, 15]);
NativeWorkbench.addShapedRecipe({
    id: 165,
    count: 1,
    data: 0
}, ["SSS", "SSS", "SSS"], ["S", 341, 0]);
NativeWorkbench.addShapelessRecipe({
    id: 341,
    count: 9,
    data: 0
}, [{
    id: 165,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 385,
    count: 3,
    data: 0
}, [{
    id: 377,
    data: 0
}, {
    id: 263,
    data: 0
}, {
    id: 289,
    data: 0
}]);
NativeWorkbench.addShapelessRecipe({
    id: 385,
    count: 3,
    data: 0
}, [{
    id: 377,
    data: 0
}, {
    id: 263,
    data: 1
}, {
    id: 289,
    data: 0
}]);
NativeWorkbench.addShapedRecipe({
    id: 420,
    count: 2,
    data: 0
}, ["~~ ", "~O ", "  ~"], ["~", 287, 0, "O", 341, 0]);
NativeWorkbench.addShapedRecipe({
    id: 416,
    count: 1,
    data: 0
}, ["X X", "XXX", "X X"], ["X", 334, 0]);
var ParticleAnimator = {
    addParticle: function(a, b, c, d, e, f, g, h) {
        MainThread.push(function() {
            Level.addParticle(d, a, b, c, e, f, g, h)
        })
    },
    line: function(a, b, c, d, e, f) {
        d = d || 1;
        var g = c.x - b.x,
            h = c.y - b.y;
        c = c.z - b.z;
        e = e || {
            x: 0,
            y: 0,
            z: 0
        };
        var k = Math.sqrt(g * g + h * h + c * c);
        g /= k;
        h /= k;
        c /= k;
        for (var m = 0; m < k; m += Math.random() * d * 2) this.addParticle(b.x + g * m, b.y + h * m, b.z + c * m, a, e.x, e.y, e.z, f)
    }
};
Translation = {
    currentLanguage: {
        id: null,
        full: null
    },
    allTranslations: {},
    refreshLanguage: function() {
        var a = FileTools.ReadKeyValueFile("games/com.mojang/minecraftpe/options.txt");
        this.currentLanguage.full = a.game_language || "en_US";
        this.currentLanguage.id = this.currentLanguage.full.substring(0, 2)
    },
    addTranslation: function(a, b) {
        this.allTranslations[a] = b
    },
    getLanguage: function() {
        return this.currentLanguage.full
    },
    translate: function(a) {
        var b = this.allTranslations[a];
        if (b) {
            var c = this.currentLanguage.id,
                d = this.currentLanguage.full;
            if (b[d]) return b[d];
            if (b[c]) return b[c]
        }
        return a
    },
    translateSentence: function(a) {
        a = (a + "").split(" ");
        var b = [],
            c;
        for (c in worlds) b[c] = this.translate(a[c]);
        return b.join(" ")
    },
    translateItem: function(a) {
        a += "";
        if ("@" == a.substring(0, 1)) {
            a = a.substring(1, a.length);
            a = a.split("|");
            for (var b in a) a[b] = this.translate(a[b]);
            return "@" + a.join("|")
        }
        return this.translate(a)
    },
    translateAllItems: function() {
        Logger.Log("localizing all blocks & items to " + this.currentLanguage.id + "(" + this.currentLanguage.full + ")", "LANG");
        for (var a = 0; 256 > a; a++) ModPE.langEdit(Item.getName(a, 0, !0), this.translateItem(Item.getName(a, 0, !1)));
        for (var b in IdentifierRegistry.data.item) a = IdentifierRegistry.data.item[b], ModPE.langEdit(Item.getName(a, 0, !0), this.translate(Item.getName(a, 0, !1)))
    }
};
Translation.refreshLanguage();
Callback.addCallback("LevelLoaded", function() {
    Translation.translateAllItems()
});
Callback.addCallback("CoreConfigured", function() {
    var a = coreEngineConfig.access("util.show_item_data_values");
    (coreEngineConfig.access("util.show_item_names") || a) && Callback.addCallback("tick", function() {
        var b = PlayerAPI.getCarriedItem();
        if (8192 <= b.id || a) {
            var c = ItemRegistry.getName(b.id, b.data);
            c && (a && (c += " [" + b.id + ", " + b.data + "]"), GameAPI.tipMessage("\n\n\n\n" + c))
        }
    })
});
Callback.addCallback("CoreConfigured", function() {
    if (coreEngineConfig.access("perfomance.auto_save")) {
        var a = 20 * Math.max(coreEngineConfig.access("perfomance.auto_save_delay"), 10) || 600;
        Callback.addCallback("tick", function() {
            0 == WorldAPI.getWorldTime() % a && SavesFunctions.write()
        })
    }
});

function initPrintStacking() {
    var a = print,
        b = null;
    GuiUtils.Run(function() {
        b = new android.os.Handler
    });
    var c = [];
    print = function(d) {
        b ? (0 == c.length && GuiUtils.Run(function() {
            b.postDelayed({
                run: function() {
                    try {
                        android.widget.Toast.makeText(getMcContext(), c.join("\n"), 0).show(), c = []
                    } catch (e) {}
                }
            }, 1250)
        }), c.push(d + "")) : a(d + "")
    }
}
Callback.addCallback("CoreConfigured", function() {
    coreEngineConfig.access("util.stack_alert_messages") && initPrintStacking()
});
var CoreAPI = {
    getCoreAPILevel: function() {
        return CORE_ENGINE_API_LEVEL
    },
    runOnMainThread: function(a) {
        MainThread.push(a)
    },
    getMCPEVersion: getMCPEVersion,
    Debug: {
        sysTime: function() {
            return java.lang.System.currentTimeMillis()
        },
        addParticle: function(a, b, c, d, e, f, g, h) {
            Level.addParticle(d, a, b, c, e, f, g, h)
        },
        message: function(a) {
            clientMessage(ChatColor.DARK_GREEN + "DEBUG: " + new String(a))
        },
        warning: function(a) {
            clientMessage(ChatColor.GOLD + "WARNING: " + new String(a))
        },
        error: function(a) {
            clientMessage(ChatColor.DARK_RED +
                "ERROR: " + new String(a))
        },
        m: function() {
            var a = [],
                b;
            for (b in arguments) {
                var c = arguments[b];
                "object" == typeof c ? a.push(JSON.stringify(c)) : a.push("" + c)
            }
            this.message(a.join(", "))
        },
        bitmap: function(a, b) {
            GuiUtils.Run(function() {
                var c = getMcContext(),
                    d = android.app.AlertDialog.Builder(c);
                b && d.setTitle(b + "");
                c = new android.widget.ImageView(c);
                c.setImageBitmap(a);
                d.setView(c);
                d.show()
            })
        }
    },
    FileTools: FileTools,
    Logger: Logger,
    Translation: Translation,
    Threading: Threading,
    UI: GuiAPI,
    UpdatableAPI: UpdatableAPI,
    Updatable: UpdatableAPI,
    UpdatableSaver: UpdatableSaver,
    TileEntity: TileEntity,
    MobRegistry: MobRegistry,
    MobSpawnRegistry: EntitySpawnRegistry,
    Callback: Callback,
    GameObject: GameObject,
    GameObjectRegistry: GameObjectRegistry,
    ModAPI: ModAPI,
    Saver: SaverAPI,
    World: WorldAPI,
    Entity: EntityAPI,
    Player: PlayerAPI,
    Game: GameAPI,
    Render: RenderAPI,
    Texture: Texture,
    EntityModel: ModelAPI,
    EntityModelWatcher: ModelWatcher,
    EntityAIClass: EntityAI,
    EntityAIWatcher: EntityAIWatcher,
    EntityAI: {
        Idle: EntityAIIdle,
        Follow: EntityAIFollow,
        Panic: EntityAIPanic,
        Wander: EntityAIWander,
        Attack: EntityAIAttack,
        Swim: EntityAISwim,
        PanicWatcher: EntityAIPanicWatcher
    },
    GenerationUtils: WorldGenerationUtils,
    Animation: {
        base: AnimationBase,
        Base: AnimationBase,
        text: AnimationText,
        Text: AnimationText,
        item: AnimationItem,
        Item: AnimationItem
    },
    Particles: ParticleAnimator,
    IDRegistry: IdentifierRegistry,
    IDData: IdentifierRegistry.data,
    ItemID: IdentifierRegistry.data.item,
    BlockID: IdentifierRegistry.data.block,
    Block: BlockRegistry,
    Item: ItemRegistry,
    Recipes: RecipeRegistry,
    ToolAPI: ToolAPI,
    Armor: ArmorRegistry,
    LiquidRegistry: LiquidRegistry,
    Unlimited: {
        API: UnlimitedAPI,
        Access: UnlimitedAPIAccess
    },
    Native: {
        ArmorType: ArmorType,
        ItemCategory: ItemCategory,
        ParticleType: ParticleType,
        Color: ChatColor,
        EntityType: EntityType,
        MobRenderType: EntityRenderType,
        PotionEffect: MobEffect,
        Dimension: DimensionId,
        ItemAnimation: UseAnimation,
        BlockSide: BlockFace,
        Enchantment: Enchantment,
        EnchantType: EnchantType,
        BlockRenderLayer: BlockRenderLayer
    }
};
CoreAPI.UpdatableAPI.Updatable = Updatable;

function ResetInGameAPIs() {
    UpdatableAPI.resetEngine();
    TileEntity.resetEngine();
    ToolAPI.resetEngine();
    EntityDataRegistry.resetEngine();
    WorldGeneration.resetEngine();
    GameObjectRegistry.resetEngine()
}

function ConfigReader(a) {
    this.file = a;
    this.config = {};
    this.isLoaded = !1;
    this.load = function() {
        FileTools.isExists(this.file) ? (this.config = FileTools.ReadJSON(this.file), this.isLoaded = !0) : (Logger.Log("config for " + this.file + " cannot be loaded: file not exists, if this is standart mod config, it will be auto-generated", "WARNING"), this.isLoaded = !1);
        this.config || (Logger.Log("config for " + this.file + " loaded empty", "WARNING"), this.isLoaded = !1)
    };
    this.save = function() {
        this.config ? FileTools.WriteJSON(this.file, this.config, !0) : Logger.Log("config for " + this.file + " is empty, cannot save it", "WARNING")
    };
    this.clear = function() {
        this.config = {}
    };
    this.get = function() {
        return this.config
    };
    this.access = function(a) {
        try {
            return eval("this.config." + a)
        } catch (c) {
            return Logger.Log("config for " + this.file + " cannot access address " + a + " : " + c, "ERROR"), null
        }
    };
    this.checkAndRestore = function(a) {
        this.__copyMissingValues(this.config, a);
        this.save()
    };
    this.__copyMissingValues = function(a, c) {
        for (var b in c) {
            var e = a[b];
            "undefined" == typeof e && (a[b] = c[b]);
            "object" == typeof e && this.__copyMissingValues(e, c[b])
        }
    };
    this.load()
}
var coreEngineConfig = new ConfigReader(FileTools.workdir + "config.json");
coreEngineConfig.access("__version_lock__") != CORE_ENGINE_CONFIG_LOCK && (Logger.Log("recreating core engine config because its outdated, all params will be set to defaults", "CORE"), GameAPI.dialogMessage("Core Engine config file is outdated and recreated because of massive changes of new version, all params was set to default, if you need it, change them again.\n\n\u0424\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Core Engine \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0438\u0437-\u0437\u0430 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u043d\u0435\u043c, \u0432\u0441\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0431\u044b\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043f\u0435\u0440\u0435\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0438\u0445, \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e.", "CONFIG UPDATED"),
    coreEngineConfig.clear());
coreEngineConfig.checkAndRestore({
    __version_lock__: CORE_ENGINE_CONFIG_LOCK,
    perfomance: {
        run_on_main_thread: !1,
        max_updates: 64,
        thread_priority: 5,
        auto_save: !0,
        auto_save_delay: 30,
        world_generator: {
            thread_optimization: !1,
            generation_thread_priority: 15,
            delay: 2,
            radius: 3,
            underground_radius: 1
        },
        entity: {
            despawn_unloaded_entities: !0,
            unloaded_despawn_time_in_secs: 1500
        }
    },
    gui: {
        faster_render: !1,
        generate_block_icons: !0,
        block_icon_size: 96,
        gui_background_thread_priority: -5,
        force_priority_change: !1,
        gui_render_thread_priority: -17
    },
    debug: {
        extend_log: !1,
        show_log_errors: !0,
        show_log_anyway: !1,
        log_generation_time_data: !1
    },
    util: {
        show_item_names: !0,
        show_item_data_values: !1,
        stack_alert_messages: !0,
        alternative_item_model: !1,
        pocket_workbench_style: !0,
        split_pocket_workbench_to_pages: !0,
        skyblock_maps_support: !0,
        force_entity_rotation: !0
    },
    modpe: {
        handle_modpe_scripts: !0,
        dump_compiled_scripts: !1,
        call_new_level_at_load: !0
    }
});
Callback.addCallback("CoreConfigured", function(a) {
    a.access("debug.extend_log") && (LOG_MAX_LIST_LENGTH = 999999)
});
UpdatableAPI.setMaxUpdateCalls(coreEngineConfig.access("perfomance.max_updates"));
BlockRegistry.setGuiIconParams(coreEngineConfig.access("gui.generate_block_icons"), coreEngineConfig.access("gui.block_icon_size"));
Callback.invokeCallback("CoreConfigured", coreEngineConfig);

function ModLibrary(a) {
    this.path = a;
    this.source = this.name = this.file = null;
    this.isLoaded = !1;
    this.load = function() {
        this.isLoaded = !1;
        FileTools.isExists(this.path) ? (this.file = new java.io.File(this.path), this.name = this.file.getName() + "", this.name.endsWith(".js") && (this.name = this.name.substr(0, this.name.length - 3)), this.source = FileTools.ReadText(this.path), LibraryLoader.isLibraryLoaded(this.name) || (this.source ? this.isLoaded = !0 : Logger.Log("cannot load library from path " + this.path + ": source code is missing or loaded with error",
            "ERROR"))) : Logger.Log("cannot load library from path " + this.path + ": file does not exists", "ERROR")
    };
    this.apiUnits = {};
    this.registerAPIUnit = function(a, c) {
        this.apiUnits[a] = c
    };
    this.importAPI = function(a) {
        var b = {};
        if ("*" == a)
            for (var d in this.apiUnits) b[d] = this.apiUnits[d];
        else b[a] = this.apiUnits[a];
        return b
    };
    this.getScope = function() {
        var a = this,
            c = {
                __name__: this.name,
                __dir__: this.path,
                __config__: null,
                __mod__: this,
                alert: function(a) {
                    print(a)
                },
                CoreAPI: CoreAPI,
                registerAPIUnit: function(b, c) {
                    a.registerAPIUnit(b,
                        c)
                }
            },
            d;
        for (d in CoreAPI) c[d] = CoreAPI[d];
        return c
    };
    this.initLib = function() {
        if (this.isLoaded) {
            var a = this.getScope(),
                a = LoadScriptWithGivenScope(this.source, a, "lib:" + this.name);
            a.error && (Logger.Log("error occured in library init: " + this.name, "ERROR"), Logger.LogError(a.error));
            LibraryLoader.registerLibrary(this)
        } else Logger.Log("cannot init library " + this.name + ": it is not loaded", "ERROR")
    }
}
var LibraryLoader = {
        loadedLibs: {},
        registerLibrary: function(a) {
            this.loadedLibs[a.name] = a
        },
        isLibraryLoaded: function(a) {
            return this.loadedLibs[a]
        },
        loadFile: function(a) {
            a = new ModLibrary(a);
            a.load();
            a.initLib()
        },
        loadDir: function(a) {
            a = FileTools.GetListOfFiles(a);
            for (var b in a) this.loadFile(a[b].getAbsolutePath())
        },
        importLib: function(a, b) {
            var c = LibraryLoader.loadedLibs[a];
            if (c) {
                var c = c.importAPI(b),
                    d;
                for (d in c) this[d] = c[d]
            } else Logger.Log("failed to import " + b + " from " + a + ": library " + a + " does not exist",
                "ERROR")
        }
    },
    ModPEAPIExtension = {
        extensionSource: null,
        debugDirectory: "/mnt/shared/shared/core-engine/loader/modpe/modpe-extension.api",
        assetDirectory: "script/modpe-extension.api",
        loadSource: function() {
            FileTools.isExists(this.debugDirectory) && (this.extensionSource = FileTools.ReadText(this.debugDirectory), Logger.Log("ModPE API extension loaded from debug directory", "LOADER"));
            this.extensionSource || (this.extensionSource = FileTools.ReadTextAsset(this.assetDirectory));
            this.extensionSource || Logger.Log("ModPE API extension cannot be loaded, all modpe mods will be disabled",
                "ERROR")
        },
        getStandartScope: function() {
            return {
                CoreAPI: CoreAPI,
                __CallbackModule: Callback,
                __IDRegistry: IdentifierRegistry,
                __UnlimitedAPI: UnlimitedAPI,
                addItemInventory: addItemInventory,
                bl_setMobSkin: bl_setMobSkin,
                bl_spawnMob: bl_spawnMob,
                clientMessage: clientMessage,
                explode: explode,
                getCarriedItem: getCarriedItem,
                getLevel: getLevel,
                getPitch: getPitch,
                getPlayerEnt: getPlayerEnt,
                getPlayerX: getPlayerX,
                getPlayerY: getPlayerY,
                getPlayerZ: getPlayerZ,
                getTile: getTile,
                getYaw: getYaw,
                preventDefault: preventDefault,
                print: print,
                rideAnimal: rideAnimal,
                setNightMode: setNightMode,
                setPosition: setPosition,
                setPositionRelative: setPositionRelative,
                setRot: setRot,
                setTile: setTile,
                setVelX: setVelX,
                setVelY: setVelY,
                setVelZ: setVelZ,
                spawnChicken: spawnChicken,
                spawnCow: spawnCow,
                spawnPigZombie: spawnPigZombie,
                ModPE: ModPE,
                Level: Level,
                Block: Block,
                Item: Item,
                Entity: Entity,
                Player: Player,
                Server: Server,
                Renderer: Renderer,
                ChatColor: ChatColor,
                ArmorType: ArmorType,
                ItemCategory: ItemCategory,
                ParticleType: ParticleType,
                EntityType: EntityType,
                EntityRenderType: EntityRenderType,
                MobEffect: MobEffect,
                DimensionId: DimensionId,
                UseAnimation: UseAnimation,
                BlockFace: BlockFace,
                Enchantment: Enchantment,
                EnchantType: EnchantType,
                BlockRenderLayer: BlockRenderLayer
            }
        },
        getExtensionSource: function() {
            return this.extensionSource
        },
        compileModPESource: function(a) {
            var b = {
                    "Player.getCarriedItemData": "Player.getCarried_ItemData",
                    "Player.getCarriedItemCount": "Player.getCarried_ItemCount",
                    "Level.getChestSlotData": "Level.getChest_SlotData",
                    "Level.getChestSlotCount": "Level.getChest_SlotCount",
                    "Level.getFurnaceSlotData": "Level.getFurnace_SlotData",
                    "Level.getFurnaceSlotCount": "Level.getFurnace_SlotCount",
                    "Player.getInventorySlotData": "Player.getInventory_SlotData",
                    "Player.getInventorySlotCount": "Player.getInventory_SlotCount"
                },
                c = {
                    _origin: "_ORIGIN",
                    setTile: "__setTile",
                    getTile: "__getTile",
                    addItemInventory: "__addItemInventory",
                    getCarriedItem: "__getCarriedItem",
                    "Level.getData": "__Level_getData",
                    "Level.getChestSlot": "__Level_getChestSlot",
                    "Level.getChest_SlotData": "__Level_getChestSlotData",
                    "Level.getFurnaceSlot": "__Level_getFurnaceSlot",
                    "Level.getFurnace_SlotData": "__Level_getFurnaceSlotData",
                    "Level.dropItem": "__Level_dropItem",
                    "Player.getCarried_ItemData": "__Player_getCarriedItemData",
                    "Player.addItemCreativeInv": "__Player_addItemCreativeInv",
                    "Player.getInventorySlot": "__Player_getInventorySlot",
                    "Player.getInventory_SlotData": "__Player_getInventorySlotData",
                    "Player.getPointedBlockId": "__Player_getPointedBlockId",
                    "Player.getPointedBlockData": "__Player_getPointedBlockData",
                    "Entity.setCarriedItem": "__Entity_setCarriedItem",
                    "Entity.getItemEntityId": "__Entity_getItemEntityId",
                    "Entity.getItemEntityData": "__Entity_getItemEntityData",
                    "Item.addShapedRecipe": "__Item_addShapedRecipe",
                    "Item.addCraftRecipe": "__Item_addCraftRecipe",
                    "Item.addFurnaceRecipe": "__Item_addFurnaceRecipe",
                    "Item.getName": "__Item_getName",
                    "Item.isValidItem": "__Item_isValidItem",
                    "Item.setCategory": "__Item_setCategory",
                    "Item.setMaxDamage": "__Item_setMaxDamage",
                    "Item.setEnchantType": "__Item_setEnchantType",
                    "Item.setHandEquipped": "__Item_setHandEquipped",
                    "Item.setProperties": "__Item_setProperties",
                    "Item.setStackedByData": "__Item_setStackedByData",
                    "Item.setUseAnimation": "__Item_setUseAnimation",
                    "ModPE.setItem": "__setItem_base",
                    "ModPE.setFoodItem": "__setItem_food",
                    "Item.defineThrowable": "__setItem_throwable",
                    "Item.defineArmor": "__setItem_armor",
                    "Block.setShape": "__Block_setShape",
                    "Block.setDestroyTime": "__Block_setDestroyTime",
                    "Block.setExplosionResistance": "__Block_setExplosionResistance",
                    "Block.setFriction": "__Block_setFriction",
                    "Block.setLightLevel": "__Block_setLightLevel",
                    "Block.setLightOpacity": "__Block_setLightOpacity",
                    "Block.setRedstoneConsumer": "__Block_setRedstoneConsumer",
                    "Block.setRenderLayer": "__Block_setRenderLayer",
                    "Block.setRenderType": "__Block_setRenderType",
                    "Block.defineBlock": "__Block_defineBlock",
                    "Block.defineLiquidBlock": "__Block_defineLiquidBlock",
                    "ModPE.log": "__ModPE_log"
                },
                d = {
                    "Player.getCarried_ItemCount": "Player.getCarriedItemCount",
                    "Level.getChest_SlotCount": "Level.getChestSlotCount",
                    "Level.getFurnace_SlotCount": "Level.getFurnaceSlotCount",
                    "Player.getInventory_SlotCount": "Player.getInventorySlotCount"
                },
                e;
            for (e in b) a = a.replace(new RegExp(e, "g"), b[e]);
            for (e in c) a = a.replace(new RegExp(e, "g"), c[e]);
            for (e in d) a = a.replace(new RegExp(e, "g"), d[e]);
            return a
        },
        isErrorState: function() {
            return !this.extensionSource
        },
        compiledSourceDumpDir: "games/com.mojang/modpe/",
        dumpCompiledSource: function(a, b) {
            FileTools.WriteText(this.compiledSourceDumpDir + b + ".compiled", a)
        }
    };
ModPEAPIExtension.loadSource();

function ModPEScript(a) {
    this.path = a;
    this.modSource = this.modName = this.file = null;
    this.isLoaded = !1;
    this.loadMod = function() {
        this.file = new java.io.File(this.path);
        if (!this.file.exists()) return Logger.Log("cannot load ModPE script from file " + this.path + ": file doesnt exists", "ERROR"), !1;
        this.modSource = FileTools.ReadText(this.path);
        if (null == this.modSource) return Logger.Log("cannot load ModPE script from file " + this.path + ": source code cannot be loaded", "ERROR"), !1;
        this.modName = this.file.getName() + "";
        return this.isLoaded = !0
    };
    this.initScriptScope = function() {
        var a = ModPEAPIExtension.getStandartScope();
        this.idMap = {
            __unique: {
                prefix: "m_" + this.modName
            }
        };
        a.__idMap = this.idMap;
        a.__MOD_NAME__ = this.modName;
        a.__idMap_itemId = IdentifierRegistry.data.item;
        a.__idMap_blockId = IdentifierRegistry.data.block;
        return a
    };
    this.launchMod = function() {
        if (!this.isLoaded) return Logger.Log("cannot launch ModPE script from file " + this.path + ": script not loaded", "ERROR"), !1;
        try {
            Logger.Log("preparing and compiling modpe script: " + this.modName, "MOD");
            if (ModPEAPIExtension.isErrorState()) return Logger.Log("error in compiling modpe script " + this.modName + ": ModPE extension source cannot be loaded", "ERROR"), !1;
            var a = ModPEAPIExtension.getExtensionSource() + "\n" + ModPEAPIExtension.compileModPESource(this.modSource);
            var c = this.initScriptScope();
            coreEngineConfig.access("modpe.dump_compiled_scripts") && ModPEAPIExtension.dumpCompiledSource(a, this.modName)
        } catch (d) {
            return Logger.Log("error in compiling modpe script: " + this.modName, "ERROR"), Logger.LogError(d), !1
        }
        Logger.Log("running modpe script: " + this.modName, "MOD");
        c = LoadScriptWithGivenScope(a, c, "[modpe] " + this.modName);
        return c.error ? (Logger.LogError(c.error), !1) : !0
    }
}
var modpeScriptList = [],
    modpeDirectoryList = [],
    ModPELoadHelper = {
        LoadFile: function(a) {
            var b = a.getName() + "";
            b.endsWith(".js") ? this.LoadScript(a) : b.endsWith(".zip") ? this.LoadZipResources(a) : b.endsWith(".modpkg") && this.LoadModPackage(a)
        },
        LoadScript: function(a) {
            a = new ModPEScript(a.getAbsolutePath());
            a.loadMod() && (modpeScriptList.push(a), a.launchMod())
        },
        LoadZipResources: function(a) {
            a.exists() && addTexturePack(a)
        },
        LoadModPackage: function(a) {
            Logger.Log("mod package at " + a + " cannot be loaded: mod packages are not supported for now",
                "ERROR")
        }
    };

function LoadMods_ModPEScript() {
    if (coreEngineConfig.access("modpe.handle_modpe_scripts")) {
        modpeDirectoryList = FileTools.GetListOfFiles(FileTools.modpedir);
        for (var a in modpeDirectoryList) ModPELoadHelper.LoadFile(modpeDirectoryList[a]);
        coreEngineConfig.access("modpe.call_new_level_at_load") && Callback.invokeCallback("ModPELevelCall");
        Logger.Log("Loaded " + modpeScriptList.length + " ModPE scripts", "LOADER")
    }
}
var DEFAULT_MOD_LAUNCHER_SOURCE = "Launch();",
    STATE_MOD_CREATED = 0,
    STATE_MOD_PREPARED = 1,
    STATE_MOD_LAUNCHED = 2,
    STATE_MOD_LOADED = 3,
    STATE_MOD_DISABLED = 4;

function Mod(a) {
    FileTools.isExists(a + "/.redirect") && (newDirectory = (FileTools.ReadText(a + "/.redirect") + "").trim()) && (Logger.Log("mod with directory " + a + " is redirected to " + newDirectory, "MOD"), a = newDirectory);
    this.directory = a + "/";
    this.guiDirectory = this.diredtory + "gui/";
    this.libDirectory = this.directory + "lib";
    this.launcherFile = this.directory + "launcher.js";
    this.codeFile = this.directory + "main.js";
    this.directoryName = ("" + a).split("/").pop();
    this.launcherSource = this.scriptSource = null;
    this.__state = STATE_MOD_CREATED;
    this.loadMod = function() {
        if (FileTools.isExists(this.directory))
            if (this.config = new ConfigReader(this.directory + "config.json"), this.config.checkAndRestore({
                    enabled: !0,
                    show_resource_errors: !0
                }), this.config.access("enabled")) {
                if (FileTools.isExists(this.directory + "mod.info")) {
                    var b = this.directory + "mod.info";
                    this.info = FileTools.ReadJSON(b);
                    var c = !1,
                        d;
                    for (d in this.info) {
                        c = !0;
                        break
                    }
                    c || (this.info = FileTools.ReadKeyValueFile(b)) && Logger.Log("old format mod.info file found, updating...", "MOD");
                    FileTools.WriteJSON(b,
                        this.info, !0);
                    this.modName = this.info.name || this.directoryName
                } else Logger.Log("mod.info file is not found", "MOD"), this.modName = this.directoryName;
                if (FileTools.isExists(this.directory + "gui")) {
                    this.guiFileList = FileTools.GetListOfFiles(this.directory + "gui");
                    b = [];
                    for (d in this.guiFileList) {
                        var c = this.guiFileList[d],
                            e = GuiUtils.GetGuiAssetName(c.getName());
                        b.push(e);
                        GuiWindowProvider.Images[e] = FileTools.ReadImage(c)
                    }
                    Logger.LogList("gui files loaded: ", b, "MOD")
                }
                FileTools.isExists(this.directory + "resources.json") ||
                    (Logger.Log("resources.json file is missing for mod " + this.modName + ", creating default one", "WARNING"), FileTools.WriteJSON(this.directory + "resources.json", {
                        "resources.zip": !0
                    }, !0));
                this.refreshResourceList();
                if (FileTools.isExists(this.directory + "dev"))
                    if (Logger.Log("mod loaded in developer mode, compiling...", "MOD"), FileTools.isExists(this.directory + "dev/.includes")) {
                        var f = FileTools.ReadText(this.directory + "dev/.includes");
                        if (f) {
                            b = [];
                            e = c = "";
                            f = f.split("\n");
                            for (d in f) {
                                var g = f[d];
                                if (g) {
                                    var h = FileTools.ReadText(this.directory +
                                        "dev/" + g);
                                    null != h ? (b.push(g), e += h + "\n\n") : c += g + ","
                                }
                            }
                            FileTools.WriteText(this.directory + "main.js", e);
                            Logger.LogList("files loaded: ", b, "MOD");
                            c && Logger.LogError("some files are not loaded: " + c, "ERROR")
                        } else Logger.Log(".includes file loaded empty, developer mode not loaded...", "MOD")
                    } else Logger.Log(".include file is missing, developer mode not loaded", "ERROR");
                FileTools.isExists(this.libDirectory) && (Logger.Log("loading libraries for " + this.modName, "LOADER"), LibraryLoader.loadDir(this.libDirectory));
                this.launcherSource = FileTools.ReadText(this.launcherFile);
                null == this.launcherSource && (Logger.Log("launcher script" + this.launcherFile + " is missing or cannot be loaded, creating default one", "MOD"), this.launcherSource = DEFAULT_MOD_LAUNCHER_SOURCE, FileTools.WriteText(this.launcherFile, this.launcherSource));
                FileTools.isExists(this.codeFile) ? (this.scriptSource = FileTools.ReadText(this.codeFile), null == this.scriptSource ? (Logger.Log("some error occured, source file not loaded, loading aborted", "ERROR"), this.__state =
                    STATE_MOD_DISABLED) : (this.modLoaded = !0, this.__state = STATE_MOD_PREPARED)) : (Logger.Log("source file " + this.codeFile + " is missing, mod loading aborted", "ERROR"), this.__state = STATE_MOD_DISABLED)
            } else Logger.Log("mod for directory " + this.directory + " is disabled, loading aborted", "MOD"), this.__state = STATE_MOD_DISABLED;
        else Logger.Log("mod cannot be loaded, mod directory " + a + " is not found, loading aborted", "ERROR"), this.__state = STATE_MOD_DISABLED
    };
    this.refreshResourceList = function() {
        this.resourceList = FileTools.ReadJSON(this.directory +
            "resources.json");
        for (var a in this.resourceList) setResourcePack(this.directory + a, this.resourceList[a], !this.config.access("show_resource_errors"))
    };
    this.getScope = function(a) {
        var b = this,
            d = {
                __name__: this.modName,
                __dir__: this.directory,
                __config__: this.config,
                __mod__: this,
                alert: function(a) {
                    print(a)
                },
                Resources: {
                    getResourceList: function() {
                        return b.resourceList
                    },
                    setResourceList: function(a) {
                        FileTools.WriteJSON(b.directory + "resources.json", a, !0);
                        b.refreshResourceList()
                    },
                    setResourcePack: setResourcePack
                },
                importLib: LibraryLoader.importLib,
                CoreAPI: CoreAPI
            },
            e;
        for (e in CoreAPI) d[e] = CoreAPI[e];
        for (e in a) d[e] = a[e];
        return d
    };
    this.runLauncher = function() {
        if (this.__state != STATE_MOD_DISABLED) {
            null == this.launcherSource && (Logger.Log("Mods launcher " + this.modName + " source is missing, launching mod immediately", "WARNING"), this.runMod());
            var a = this,
                c = this.getScope({
                    Launch: function(b) {
                        a.runMod(b)
                    }
                });
            Logger.Log("running mod launcher script: " + this.modName, "MOD");
            c = LoadScriptWithGivenScope(this.launcherSource, c, this.modName + " launcher");
            c.error && Logger.LogError(c.error);
            this.__state < STATE_MOD_LAUNCHED && (this.__state = STATE_MOD_LAUNCHED)
        }
    };
    this.runMod = function(a) {
        this.__state != STATE_MOD_DISABLED && (null == this.scriptSource ? Logger.Log("Mod " + this.modName + " source is missing, cannot launch ", "ERROR") : (a = this.getScope(a), Logger.Log("running mod: " + this.modName, "MOD"), a = LoadScriptWithGivenScope(this.scriptSource, a, this.modName), a.error && Logger.LogError(a.error), this.__state = STATE_MOD_LOADED, Callback.invokeCallback("ModLoaded:" + this.modName, this)))
    }
}
var modList = [],
    modDirectoryList = [];

function LoadMods_CoreEngine() {
    modDirectoryList = FileTools.GetListOfDirs(FileTools.moddir);
    for (var a in modDirectoryList) {
        var b = modDirectoryList[a];
        Logger.Log("found mod directory " + b + ", loading mod", "LOADER");
        b = new Mod(b);
        modList.push(b);
        b.loadMod();
        b.runLauncher(!0)
    }
    Callback.invokeCallback("ModDirLoaded");
    Logger.Log("Loaded " + modList.length + " CoreEngine mods", "LOADER")
}
var __texturePackChanged = !1;

function addTexturePack(a) {
    var b = net.zhuoweizhang.mcpelauncher.Utils,
        c = b.getPrefs(0).edit(),
        d = b.getPrefs(1).edit();
    c.putBoolean("zz_texture_pack_enable", !0);
    c.apply();
    var c = (a.getAbsolutePath() + "").split("/").join("/"),
        b = JSON.parse(b.getPrefs(1).getString("texture_packs", "[]")),
        e;
    for (e in b)
        if (b[e].p == c) {
            Logger.Log("Loading resources " + a + ": already loaded", "LOADER");
            return
        }
    b ? b.push({
        t: "zip",
        p: c
    }) : b = [{
        t: "zip",
        p: c
    }];
    d.putString("texture_packs", JSON.stringify(b));
    d.apply();
    __texturePackChanged = !0;
    Logger.Log("Loading resources " +
        a + ": loaded first time, core engine will be restarted", "LOADER")
}

function removeTexturePack(a) {
    var b = net.zhuoweizhang.mcpelauncher.Utils,
        c = b.getPrefs(0).edit(),
        d = b.getPrefs(1).edit();
    c.putBoolean("zz_texture_pack_enable", !0);
    c.apply();
    var c = (a.getAbsolutePath() + "").split("/").join("/"),
        b = JSON.parse(b.getPrefs(1).getString("texture_packs", "[]")),
        e;
    for (e in b) b[e].p == c && (b.splice(e--, 1), Logger.Log("Removing resources " + a + ": resources removed, core engine will be restarted", "LOADER"), __texturePackChanged = !0);
    d.putString("texture_packs", JSON.stringify(b));
    d.apply();
    Logger.Log("Removing resources " + a + ": resources not found, already removed", "LOADER")
}

function setResourcePack(a, b, c) {
    a = FileTools.getFullPath(a);
    var d = new java.io.File(a);
    if (FileTools.isExists(a)) try {
        b ? addTexturePack(d) : removeTexturePack(d)
    } catch (e) {
        Logger.Log("set resources failed", "ERROR"), Logger.LogError(e)
    } else Logger.Log("cannot set resources packs, file " + a + " does not exists", c ? "WARNING" : "ERROR"), removeTexturePack(d)
}

function LoadScriptWithGivenScope(a, b, c) {
    var d = org.mozilla.javascript.ScriptableObject,
        e = c || "<no name>",
        f = org.mozilla.javascript.Context.enter();
    f.setLanguageVersion(200);
    var g = f.initStandardObjects(null, !1);
    for (c in b) d.putProperty(g, new String(c), b[c]);
    b = {};
    try {
        b.result = f.evaluateString(g, a, e, 0, null)
    } catch (h) {
        b.error = h
    }
    return b
}
LoadMods_CoreEngine();
LoadMods_ModPEScript();
Logger.Log("All mods loaded, starting up...", "LOADER");
Callback.invokeCallback("PreBlocksDefined");
Callback.invokeCallback("BlocksDefined");
Callback.invokeCallback("PreLoaded");
Callback.invokeCallback("APILoaded");
Callback.invokeCallback("ModsLoaded");
Callback.invokeCallback("PostLoaded");
Logger.flush();
__texturePackChanged && (Logger.Log("resources was updated, restarting in few moments...", "LOADER"), Logger.flush(), Callback.invokeCallback("PreRestart"), RestartBlocklauncher());
coreEngineConfig.access("debug.show_log_anyway") ? Logger.showAsDialog("loading log", "") : coreEngineConfig.access("debug.show_log_errors") && Logger.checkErrors();




///  ============== ENTRANCE BANNER ====================
(function() {
    function getMcContext() {
        return com.mojang.minecraftpe.MainActivity.currentMainActivity.get();
    }

    function readImageAsset(name) {
        var bytes = ModPE.getBytesFromTexturePack("assets/" + name);
        var options = new android.graphics.BitmapFactory.Options();
        options.inScaled = false;
        if (bytes) {
            return android.graphics.BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
        } else {
            return null;
        }
    }

    function getDisplaySize() {
        var ctx = getMcContext();
        if (android.os.Build.VERSION.SDK_INT > 16) {
            var uiVisibility = ctx.getWindow().getDecorView().getSystemUiVisibility();
            var hideNavi = android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
            if (uiVisibility && hideNavi != 0) {
                var display = new android.util.DisplayMetrics();
                ctx.getWindowManager().getDefaultDisplay().getRealMetrics(display);
                var width = display.widthPixels;
                var height = display.heightPixels;
                return [width, height];
            }
        } else {
            Logger.Log("old SDK detected", "GUI");
        }
        var width = ctx.getWindowManager().getDefaultDisplay().getWidth();
        var height = ctx.getWindowManager().getDefaultDisplay().getHeight();
        return [width, height];
    }

    function runAsUI(func) {
        var ctx = getMcContext();
        ctx.runOnUiThread(new java.lang.Runnable({
            run: function() {
                try {
                    func();
                } catch (e) {
                    print("error during banner show: " + e);
                }
            }
        }));
    }


    var displaySize = getDisplaySize();
    var displayWidth = displaySize[0];
    var displayHeight = displaySize[0];

    var bannerImage = readImageAsset("entrance-banner.png");

    if (bannerImage) {
        var ctx = getMcContext();
        var parentWindow = ctx.getWindow().getDecorView();
        var bannerWindow = new android.widget.PopupWindow(ctx);
        var bannerView = new android.widget.ImageView(ctx);

        runAsUI(function() {
            var bannerWidth = displayWidth * .35;
            var bannerHeight = bannerWidth * .5;
            bannerWindow.setWidth(bannerWidth);
            bannerWindow.setHeight(bannerHeight);

            bannerWindow.setContentView(bannerView);
            bannerWindow.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(0));
            bannerWindow.setTouchable(false);
            bannerWindow.showAtLocation(parentWindow, android.view.Gravity.BOTTOM | android.view.Gravity.LEFT, (displayWidth - bannerWidth) * .5, 0);

            bannerView.setImageBitmap(bannerImage);

            (new java.lang.Thread({
                run: function() {
                    var alpha = 800;
                    while (alpha -= 2 > 0) {
                        runAsUI(function() {
                            bannerView.setAlpha(Math.min(100, alpha) / 100);
                        });
                        java.lang.Thread.sleep(10);
                    }
                    runAsUI(function() {
                        bannerWindow.dismiss();
                    });
                }
            })).start();
        });
    } else {
        print("cannot show banner: image cannot be loaded");
    }
})();